fixed correlation issue

master
parent 1a6b41cc7e
commit 63d46f9520
  1. 7
      css/style.css
  2. 2
      data/dataR2.csv
  3. 3
      index.html
  4. 113
      js/checkbox.js
  5. 10
      js/data_form_handler.js
  6. 3
      js/tsne.js
  7. 335
      js/tsne_vis.js

@ -220,7 +220,6 @@ rect {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
@ -310,7 +309,7 @@ rect {
}
.bar {
/*shape-rendering: crispEdges;*/
shape-rendering: crispEdges;
}
/* Styling for the annotation circle */
@ -351,7 +350,7 @@ rect {
.children-columns{
display: flex;
}
/* Margins for the extra-information panel and the kNNInfo */
#extra-information {
margin-top: 40px;
margin-left: 10px;
@ -370,6 +369,8 @@ rect {
margin-left:10px;
}
/* Draw a red colored button for reset */
#FactRes{
color: red;
}

@ -1,4 +1,4 @@
Age,BMI,Glucose,Insulin,HOMA,Leptin,Adiponectin,Resistin,MCP.1,name
Age,BMI,Glucose,Insulin,HOMA,Leptin,Adiponectin,Resistin,MCP.1,Category*
48,23.5,70,2.707,0.467408667,8.8071,9.7024,7.99585,417.114,1
83,20.69049454,92,3.115,0.706897333,8.8438,5.429285,4.06405,468.786,1
82,23.12467037,91,4.498,1.009651067,17.9393,22.43204,9.27715,554.697,1

1 Age BMI Glucose Insulin HOMA Leptin Adiponectin Resistin MCP.1 name Category*
2 48 23.5 70 2.707 0.467408667 8.8071 9.7024 7.99585 417.114 1
3 83 20.69049454 92 3.115 0.706897333 8.8438 5.429285 4.06405 468.786 1
4 82 23.12467037 91 4.498 1.009651067 17.9393 22.43204 9.27715 554.697 1

@ -12,7 +12,7 @@
<script src='./modules/d3v3/d3.min.js'></script>
<script src='./modules/d3/d3.min.js'></script>
<!-- Importing additional modules such as starPlot, annotator, tip, legend, switch, papaParse, and Jquery. -->
<!-- Importing additional modules such as starPlot, annotator, tip, legend, lasso, papaParse, and Jquery. -->
<script src='./modules/d3-star/d3-starPlot.js'></script>
<script src='./modules/d3-annotations/d3-annotator.js'></script>
<script src="./modules/d3-tip/tip.js"></script>
@ -24,7 +24,6 @@
<!-- Basic scripts that we execute. -->
<script src="./js/tsne.js"></script>
<script src="./js/checkbox.js"></script>
<script src="./js/data_form_handler.js"></script>
<script src="./modules/pca/pca.js"></script>

@ -1,113 +0,0 @@
function d3CheckBox () {
var size = 20,
x = 0,
y = 0,
rx = 0,
ry = 0,
markStrokeWidth = 3,
boxStrokeWidth = 3,
checked = false,
clickEvent;
function checkBox (selection) {
var g = selection.append("g"),
box = g.append("rect")
.attr("width", size)
.attr("height", size)
.attr("x", x)
.attr("y", y)
.attr("rx", rx)
.attr("ry", ry)
.style({
"fill-opacity": 0,
"stroke-width": boxStrokeWidth,
"stroke": "black"
});
//Data to represent the check mark
var coordinates = [
{x: x + (size / 8), y: y + (size / 3)},
{x: x + (size / 2.2), y: (y + size) - (size / 4)},
{x: (x + size) - (size / 8), y: (y + (size / 10))}
];
var line = d3.svg.line()
.x(function(d){ return d.x; })
.y(function(d){ return d.y; })
.interpolate("basic");
var mark = g.append("path")
.attr("d", line(coordinates))
.style({
"stroke-width" : markStrokeWidth,
"stroke" : "black",
"fill" : "none",
"opacity": (checked)? 1 : 0
});
g.on("click", function () {
checked = !checked;
mark.style("opacity", (checked)? 1 : 0);
if(clickEvent)
clickEvent();
d3.event.stopPropagation();
});
}
checkBox.size = function (val) {
size = val;
return checkBox;
}
checkBox.x = function (val) {
x = val;
return checkBox;
}
checkBox.y = function (val) {
y = val;
return checkBox;
}
checkBox.rx = function (val) {
rx = val;
return checkBox;
}
checkBox.ry = function (val) {
ry = val;
return checkBox;
}
checkBox.markStrokeWidth = function (val) {
markStrokeWidth = val;
return checkBox;
}
checkBox.boxStrokeWidth = function (val) {
boxStrokeWidth = val;
return checkBox;
}
checkBox.checked = function (val) {
if(val === undefined) {
return checked;
} else {
checked = val;
return checkBox;
}
}
checkBox.clickEvent = function (val) {
clickEvent = val;
return checkBox;
}
return checkBox;
}

@ -1,16 +1,20 @@
function changeDataset(value) {
var format = value.split("."); //get the actual format
if (format[value.split(".").length-1] == "csv") {
}else{
var format = value.split("."); // Get the data set's format.
if (format[value.split(".").length-1] != "csv") { // This is for a new file.
d3.select("#data").select("input").remove();
d3.select("#data")
.append("input")
.attr("type", "file")
.style("font-size", "10px")
.on("change", function() {
var file = d3.event.target.files[0];
getfile(file);
})
} else {
d3.select("#data").select("input").remove(); // Remove the selection field.
}
}

@ -1,4 +1,5 @@
// create main global object
// t-SNE Algorithm
var tsnejs = tsnejs || { REVISION: 'ALPHA' };
(function(global) {

@ -1,24 +1,40 @@
// t-SNE.js object and other global variables
// t-SNE Visualization and global variables
var k; var points = []; var all_fields; var pointsbeta = []; var KNNEnabled = true; var cost = []; var ParametersSet = []; var overallCost;
// form controls
var input;
// These are the dimensions for the square shape of the main panel\
var dimensions = document.getElementById('modtSNEcanvas').offsetWidth;
var prevRightClick; var ColorsCategorical; var Category;
// This variable is used when a new file is upload by a user.
var new_file;
// These are the dimensions for the overview panel
var dim = document.getElementById('tSNEcanvas').offsetWidth;
// The basic variables in order to execute t-SNE (opt is perplexity and learning rate).
var tsne; var opt; var step_counter; var max_counter; var runner;
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 = [];
// These variables are initialized here in order to store the final dataset, the points, the cost, the cost for each iteration, the beta values, the positions, the 2D points positions,
// In addition, there is an array which keeps the initial information of the points (i.e., initial state), the data features (with the label of the category plus the id of the point), the data features without the category (only numbers).
var final_dataset; var points = []; var cost = []; var cost_each; var beta_all = []; var x_position = []; var y_position = []; var points2d = []; var ArrayContainsDataFeatures = []; var ArrayContainsDataFeaturesCleared = []; var InitialStatePoints = [];
// The distances in the high dimensional space and in the 2D space. All the labels that were found in the selected data set.
var dists; var dists2d; var all_labels;
// These are the dimensions for the Overview view and the Main view
var dim = document.getElementById('tSNEcanvas').offsetWidth; var dimensions = document.getElementById('modtSNEcanvas').offsetWidth;
// Category = the name of the category if it exists. The user has to add an asterisk ("*") mark in order to let the program identify this feature as a label/category name.
// ColorsCategorical = the categorical colors (maximum value = 10).
var Category; var ColorsCategorical;
// Schema Investigation
// svgClick = Click a left mouse click in order to add a point.
// prevRightClick = When right click is pressed prevent any other action. Lock the current schema.
// if flagForSchema is false then send a message to the user that he/she has to: "Please, draw a schema first!");
var svgClick; var prevRightClick; var flagForSchema = false;
// Save the parameters for the current analysis, save the overallCost, and store in the "input" variable all the points and points2D.
var ParametersSet = []; var overallCost; var input;
// This function is executed when the factory button is pressed in order to bring the visualization in the initial state.
function FactoryReset(){
lassoEnable();
flag = false;
flagForSchema = false;
d3.selectAll("#modtSNEcanvas_svg_Schema > *").remove();
d3.selectAll("#SvgAnnotator > *").remove();
d3.select("#data").select("input").remove(); // Remove the selection field.
Arrayx = [];
Arrayy = [];
XYDistId = [];
@ -95,15 +111,18 @@ function FactoryReset(){
}
// Load a previously executed analysis function.
function loadAnalysis(){
document.getElementById('file-input').click();
document.getElementById("ExecuteBut").innerHTML = "Execute previous t-SNE analysis";
}
// This function is being used when the user selects to upload a new data set.
function getfile(file){
new_file = file; //uploaded file data
new_file = file; //uploaded data file
}
// Read the previous analysis, which the user wants to upload.
function fetchVal(callback) {
var file, fr;
file = input.files[0];
@ -115,24 +134,25 @@ function fetchVal(callback) {
fr.readAsText(file);
}
// Parse data
// Parse the data set
var getData = function() {
let format;
let value;
if (typeof window.FileReader !== 'function') {
alert("The file API isn't supported on this browser yet.");
}
var value;
input = document.getElementById("file-input");
if (!input) {
alert("Um, couldn't find the fileinput element.");
}
else if (!input.files) {
} else if (!input.files) {
alert("This browser doesn't seem to support the `files` property of file inputs.");
}
else if (!input.files[0]) {
value = document.getElementById("param-dataset").value;
format = document.getElementById("param-dataset").value.split("."); //get the actual format
} else if (!input.files[0]) {
value = document.getElementById("param-dataset").value; // get the value of the data set
format = document.getElementById("param-dataset").value.split("."); //get the format
if (format[value.split(".").length-1] == "csv") {
parseData("./data/"+value);
}else{
@ -168,8 +188,6 @@ function parseData(url) {
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{
@ -179,7 +197,6 @@ function parseData(url) {
}
}
}
}
return el;
});
Papa.parse(url, { //for csv file!
@ -211,7 +228,7 @@ function setReset(){
d3.selectAll("#correlation > *").remove();
d3.selectAll("#modtSNEcanvas_svg > *").remove();
lassoEnable();
flag = false;
flagForSchema = false;
d3.selectAll("#modtSNEcanvas_svg_Schema > *").remove();
d3.selectAll("#SvgAnnotator > *").remove();
Arrayx = [];
@ -259,7 +276,9 @@ function setLayerComp(){
d3.select("#modtSNEcanvas_svg").style("z-index", 2);
d3.select("#modtSNEcanvas_svg_Schema").style("z-index", 1);
d3.select("#modtSNEcanvas").style("z-index", 1);
if (points.length){
lassoEnable();
}
}
function setLayerSche(){
@ -355,6 +374,11 @@ function setAnnotator(){
.classed("shaded", function(d) { return d.shaded; });
}
} else{
// Get the checkbox.
var checkBox = document.getElementById("controls");
// Unchecked!
checkBox.checked = false;
// Print a message to the user.
alert("Cannot hide the annotators' controls because, currently, there are no annotations into the visual representation.")
}
});
@ -458,7 +482,6 @@ function init(data, results_all, fields) {
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);
@ -483,19 +506,17 @@ function init(data, results_all, fields) {
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);
for (let j = 0; j < Object.keys(dataFeatures[k]).length; j++){
if(typeof(Object.values(dataFeatures[k])[j]) == "number" && Object.keys(dataFeatures[k])[j] != Category){
object.push(Object.values(dataFeatures[k])[j]);
}
}
});
ArrayContainsDataFeaturesCleared.push(object);
}
var valCategExists = 0;
for (var i=0; i<Object.keys(dataFeatures[0]).length; i++){
if (Object.keys(dataFeatures[0])[i] == Category){
valCategExists = valCategExists + 1;
}
}
@ -792,7 +813,7 @@ d3.tsv("./modules/heat.tsv").then(function(data) {
var tip = d3.tip()
.attr('class', 'd3-tip')
.style("visibility","visible")
.offset([-20, 0])
.offset([-10, 36.5])
.html(function(d) {
return "Value: <span style='color:red'>" + Math.round(d.value);
});
@ -1114,7 +1135,6 @@ function redraw(repoints){
function handleLassoEnd(lassoPolygon) {
var countLassoFalse = 0;
KNNEnabled = true;
for (var i = 0 ; i < points.length ; i ++) {
x = points[i].x;
@ -1152,7 +1172,6 @@ function handleLassoEnd(lassoPolygon) {
// reset selected points when starting a new polygon
function handleLassoStart(lassoPolygon) {
KNNEnabled = false;
for (var i = 0 ; i < points.length ; i ++) {
points[i].selected = true;
points[i].starplot = false;
@ -1198,9 +1217,6 @@ var svg,
.on("touchmove.zoom", null)
.on("touchend.zoom", null);
var svgClick;
var flag = false;
function click(){
svgClick = d3.select('#modtSNEcanvas_svg_Schema');
@ -1251,7 +1267,7 @@ function click(){
// Prevent the default mouse action. Allow right click to be used for the confirmation of our schema.
d3.event.preventDefault();
flag = true;
flagForSchema = true;
CalculateCorrel();
}
});
@ -1259,7 +1275,7 @@ function click(){
function CalculateCorrel(){
if (flag == false){
if (flagForSchema == false){
alert("Please, draw a schema first!");
} else{
var correlLimit = document.getElementById("param-corr-value").value;
@ -1317,7 +1333,7 @@ function CalculateCorrel(){
ArrayLimit = [];
for (var i=0; i<arraysCleared.length; i++) {
if (arraysCleared[i][5] < correlLimit) {
if (arraysCleared[i][arraysCleared[0].length-2] < correlLimit) {
ArrayLimit.push(arraysCleared[i]);
}
}
@ -1326,7 +1342,7 @@ function CalculateCorrel(){
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){
if (ArrayLimit[i][ArrayLimit[0].length-5] == m){
count[m] = count[m] + 1;
temparray.push(ArrayLimit[i]);
}
@ -1361,33 +1377,60 @@ function CalculateCorrel(){
}
var Order = [];
for (var temp = 0; temp < arraysConnected.length; temp++) {
Order.push(arraysConnected[temp][6]);
Order.push(arraysConnected[temp][arraysConnected[0].length-1]);
}
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){
if (ArrayLimit[j][ArrayLimit[0].length-1] == points[i].id){
points[i].selected = true;
}
}
}
redraw(points);
for (let k = 0; k < dataFeatures.length; k++){
ArrayContainsDataFeatures.push(Object.values(dataFeatures[k]).concat(k));
ArrayContainsDataFeaturesCleared.push(ArrayContainsDataFeaturesCleared[k].concat(k));
}
ArrayContainsDataFeatures = mapOrder(ArrayContainsDataFeatures, Order, 5);
ArrayContainsDataFeaturesCleared = mapOrder(ArrayContainsDataFeaturesCleared, Order, arraysConnected[0].length-2);
ArrayContainsDataFeaturesLimit = [];
for (var i = 0; i < ArrayContainsDataFeatures.length; i++){
for (var i = 0; i < ArrayContainsDataFeaturesCleared.length; i++){
for (var j = 0; j < arraysConnected.length; j++){
if (ArrayContainsDataFeatures[i][5] == arraysConnected[j][6]){
ArrayContainsDataFeaturesLimit.push(ArrayContainsDataFeatures[i]);
if (ArrayContainsDataFeaturesCleared[i][ArrayContainsDataFeaturesCleared[0].length-1] == arraysConnected[j][arraysConnected[0].length-1]){
ArrayContainsDataFeaturesLimit.push(ArrayContainsDataFeaturesCleared[i]);
}
}
}
if (ArrayContainsDataFeaturesLimit.length == 0){
d3.selectAll("#correlation > *").remove();
d3.selectAll("#modtSNEcanvas_svg > *").remove();
flagForSchema = false;
d3.selectAll("#modtSNEcanvas_svg_Schema > *").remove();
Arrayx = [];
Arrayy = [];
XYDistId = [];
Arrayxy = [];
DistanceDrawing1D = [];
allTransformPoints = [];
p;
pFinal = [];
paths;
path;
ArrayLimit = [];
minimum;
correlationResults = [];
ArrayContainsDataFeaturesLimit = [];
prevRightClick = false;
for (var i=0; i < InitialStatePoints.length; i++){
InitialStatePoints[i].selected = true;
InitialStatePoints[i].starplot = false;
}
alert("No points selected! Please, try to increase the correlation threshold.");
redraw(InitialStatePoints);
} else {
for (var loop = 0; loop < ArrayContainsDataFeaturesLimit.length; loop++) {
ArrayContainsDataFeaturesLimit[loop].push(loop);
}
@ -1429,6 +1472,7 @@ function CalculateCorrel(){
}
drawBarChart();
}
}
}
function drawBarChart(){
@ -1960,6 +2004,7 @@ height = Math.min(width, window.innerHeight - margin.top - margin.bottom);
function BetatSNE(points){
if (points.length) {
selectedPoints = [];
var findNearestTable = [];
for (let m=0; m<points.length; m++){
@ -1968,7 +2013,7 @@ function BetatSNE(points){
}
}
if (KNNEnabled == true && selectedPoints.length != 0){
if (selectedPoints.length != 0){
var distsFull = dists;
var dists2dFull = dists2d;
@ -2008,7 +2053,7 @@ function BetatSNE(points){
$("#kNNDetails").html("Purity of the cluster was checked for k values starting from " + (1) + " to " + maxKNN + ".");
for (k=maxKNN; k>0; k--){
for (k=maxKNN; k>1; k--){
findNearest = 0;
var indexOrderSliced = [];
@ -2271,19 +2316,19 @@ function BetatSNE(points){
svg.select(".legendLinear")
.call(legend);
} else {
var max = (d3.max(points,function(d){ return d.cost; }));
var min = (d3.min(points,function(d){ return d.cost; }));
} else {
var max = (d3.max(points,function(d){ return d.cost; }));
var min = (d3.min(points,function(d){ return d.cost; }));
var maxSize2 = (d3.max(points,function(d){ return d.beta; }));
var minSize2 = (d3.min(points,function(d){ return d.beta; }));
var rscale2 = d3.scaleLinear()
var maxSize2 = (d3.max(points,function(d){ return d.beta; }));
var minSize2 = (d3.min(points,function(d){ return d.beta; }));
var rscale2 = d3.scaleLinear()
.domain([minSize2, maxSize2])
.range([5,12]);
var colorbrewer = ["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"];
var calcStep = (max-min)/9;
var colorScale = d3.scaleLinear()
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);
@ -2314,54 +2359,54 @@ var colorScale = d3.scaleLinear()
svg.select(".legendLinear")
.call(legend);
}
}
window.addEventListener('resize', () => {
window.addEventListener('resize', () => {
dimensions = window.innerWidth;
dimensions = window.innerHeight;
renderer.setSize(dimensions, dimensions);
camera.aspect = dimensions / dimensions;
camera.updateProjectionMatrix();
})
})
let zoom = d3.zoom()
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);
view = d3.select(renderer.domElement);
function setUpZoom() {
function setUpZoom() {
view.call(zoom);
let initial_scale = getScaleFromZ(far);
var initial_transform = d3.zoomIdentity.translate(dimensions/2, dimensions/2).scale(initial_scale);
zoom.transform(view, initial_transform);
camera.position.set(0, 0, far);
}
}
//if(step_counter == max_counter){
setUpZoom();
//}
//if(step_counter == max_counter){
setUpZoom();
//}
var circle_sprite= new THREE.TextureLoader().load(
var circle_sprite= new THREE.TextureLoader().load(
"./textures/circle-sprite.png"
)
)
clearThree(scene);
clearThree(scene);
// Increase/reduce size factor selected by the user
var limitdist = document.getElementById("param-lim-value").value;
limitdist = parseFloat(limitdist).toFixed(1);
// 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;
let geometry = new THREE.Geometry();
for (var i=0; i<points.length; i++) {
let pointsMaterial;
let factorPlusSize;
let geometry = new THREE.Geometry();
for (var i=0; i<points.length; i++) {
let pointsGeometry = new THREE.Geometry();
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);
@ -2416,25 +2461,25 @@ for (var i=0; i<points.length; i++) {
var particlesDuplic = new THREE.Points(geometry, pointsMaterial);
var particles = new THREE.Points(pointsGeometry, pointsMaterial);
scene.add(particles);
}
}
let tempSort = -1;
let tempSort = -1;
for (var i=0; i<points.length; i++){
if (points[i].DimON != null) {
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) {
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) {
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 = [];
@ -2462,10 +2507,10 @@ if(points[j].DimON != null) {
.call(legend);
break;
}
}
// This is for the legend
for (var j=0; j < points.length; j++){
if(temporal == 0 && points[j].DimON == null){
}
// 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");
@ -2504,56 +2549,56 @@ if(temporal == 0 && points[j].DimON == null){
break;
}
}
}
}
function zoomHandler(d3_transform) {
function zoomHandler(d3_transform) {
let scale = d3_transform.k;
let x = -(d3_transform.x - dimensions/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) {
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) {
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) {
function toRadians (angle) {
return angle * (Math.PI / 180);
}
}
// Hover and tooltip interaction
// Hover and tooltip interaction
raycaster = new THREE.Raycaster();
raycaster.params.Points.threshold = 10;
raycaster = new THREE.Raycaster();
raycaster.params.Points.threshold = 10;
view.on("mousemove", () => {
view.on("mousemove", () => {
let [mouseX, mouseY] = d3.mouse(view.node());
let mouse_position = [mouseX, mouseY];
checkIntersects(mouse_position);
});
checkIntersects(mouse_position);
});
function mouseToThree(mouseX, mouseY) {
function mouseToThree(mouseX, mouseY) {
return new THREE.Vector3(
mouseX / dimensions * 2 - 1,
-(mouseY / dimensions) * 2 + 1,
1
);
}
function checkIntersects(mouse_position) {
}
function checkIntersects(mouse_position) {
let mouse_vector = mouseToThree(...mouse_position);
raycaster.setFromCamera(mouse_vector, camera);
let intersects = raycaster.intersectObject(particlesDuplic);
@ -2577,16 +2622,16 @@ function checkIntersects(mouse_position) {
removeHighlights();
hideTooltip();
}
}
}
function sortIntersectsByDistanceToRay(intersects) {
function sortIntersectsByDistanceToRay(intersects) {
return _.sortBy(intersects, "distanceToRay");
}
}
hoverContainer = new THREE.Object3D()
scene.add(hoverContainer);
hoverContainer = new THREE.Object3D()
scene.add(hoverContainer);
function highlightPoint(datum) {
function highlightPoint(datum) {
removeHighlights();
let geometry = new THREE.Geometry();
@ -2618,30 +2663,30 @@ function highlightPoint(datum) {
let point = new THREE.Points(geometry, material);
hoverContainer.add(point);
}
}
function removeHighlights() {
function removeHighlights() {
hoverContainer.remove(...hoverContainer.children);
}
}
view.on("mouseleave", () => {
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;">
// 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);
</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');
let $tooltip = document.querySelector('#tooltip');
let $point_tip = document.querySelector('#point_tip');
let $group_tip = document.querySelector('#group_tip');
function updateTooltip() {
function updateTooltip() {
if (all_labels[0] == undefined){
var colorScaleCat = d3.scaleOrdinal().domain(["No Category"]).range(["#C0C0C0"]);
}
@ -2668,9 +2713,9 @@ function updateTooltip() {
tooltipComb = "-";
}
$group_tip.innerText = tooltipComb;
}
}
function showTooltip(mouse_position, datum) {
function showTooltip(mouse_position, datum) {
let tooltip_width = 240;
let x_offset = tooltip_width + tooltip_width;
let y_offset = 30;
@ -2691,13 +2736,13 @@ function showTooltip(mouse_position, datum) {
}
}
updateTooltip();
}
}
function hideTooltip() {
function hideTooltip() {
tooltip_state.display = "none";
updateTooltip();
}
}
}
}

Loading…
Cancel
Save