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.
206 lines
5.4 KiB
206 lines
5.4 KiB
var helper = require('./legend');
|
|
|
|
module.exports = function(){
|
|
|
|
var scale = d3.scale.linear(),
|
|
shape = "rect",
|
|
shapeWidth = 15,
|
|
shapeHeight = 15,
|
|
shapeRadius = 10,
|
|
shapePadding = 2,
|
|
cells = [5],
|
|
labels = [],
|
|
classPrefix = "",
|
|
useClass = false,
|
|
title = "",
|
|
labelFormat = d3.format(".01f"),
|
|
labelOffset = 10,
|
|
labelAlign = "middle",
|
|
labelDelimiter = "to",
|
|
orient = "vertical",
|
|
ascending = false,
|
|
path,
|
|
legendDispatcher = d3.dispatch("cellover", "cellout", "cellclick");
|
|
|
|
function legend(svg){
|
|
|
|
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter),
|
|
legendG = svg.selectAll('g').data([scale]);
|
|
|
|
legendG.enter().append('g').attr('class', classPrefix + 'legendCells');
|
|
|
|
|
|
var cell = legendG.selectAll("." + classPrefix + "cell").data(type.data),
|
|
cellEnter = cell.enter().append("g", ".cell").attr("class", classPrefix + "cell").style("opacity", 1e-6),
|
|
shapeEnter = cellEnter.append(shape).attr("class", classPrefix + "swatch"),
|
|
shapes = cell.select("g." + classPrefix + "cell " + shape);
|
|
|
|
//add event handlers
|
|
helper.d3_addEvents(cellEnter, legendDispatcher);
|
|
|
|
cell.exit().transition().style("opacity", 0).remove();
|
|
|
|
helper.d3_drawShapes(shape, shapes, shapeHeight, shapeWidth, shapeRadius, path);
|
|
|
|
helper.d3_addText(legendG, cellEnter, type.labels, classPrefix)
|
|
|
|
// sets placement
|
|
var text = cell.select("text"),
|
|
shapeSize = shapes[0].map( function(d){ return d.getBBox(); });
|
|
|
|
//sets scale
|
|
//everything is fill except for line which is stroke,
|
|
if (!useClass){
|
|
if (shape == "line"){
|
|
shapes.style("stroke", type.feature);
|
|
} else {
|
|
shapes.style("fill", type.feature);
|
|
}
|
|
} else {
|
|
shapes.attr("class", function(d){ return classPrefix + "swatch " + type.feature(d); });
|
|
}
|
|
|
|
var cellTrans,
|
|
textTrans,
|
|
textAlign = (labelAlign == "start") ? 0 : (labelAlign == "middle") ? 0.5 : 1;
|
|
|
|
//positions cells and text
|
|
if (orient === "vertical"){
|
|
cellTrans = function(d,i) { return "translate(0, " + (i * (shapeSize[i].height + shapePadding)) + ")"; };
|
|
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width + shapeSize[i].x +
|
|
labelOffset) + "," + (shapeSize[i].y + shapeSize[i].height/2 + 5) + ")"; };
|
|
|
|
} else if (orient === "horizontal"){
|
|
cellTrans = function(d,i) { return "translate(" + (i * (shapeSize[i].width + shapePadding)) + ",0)"; }
|
|
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width*textAlign + shapeSize[i].x) +
|
|
"," + (shapeSize[i].height + shapeSize[i].y + labelOffset + 8) + ")"; };
|
|
}
|
|
|
|
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign);
|
|
helper.d3_title(svg, legendG, title, classPrefix);
|
|
|
|
cell.transition().style("opacity", 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
legend.scale = function(_) {
|
|
if (!arguments.length) return scale;
|
|
scale = _;
|
|
return legend;
|
|
};
|
|
|
|
legend.cells = function(_) {
|
|
if (!arguments.length) return cells;
|
|
if (_.length > 1 || _ >= 2 ){
|
|
cells = _;
|
|
}
|
|
return legend;
|
|
};
|
|
|
|
legend.shape = function(_, d) {
|
|
if (!arguments.length) return shape;
|
|
if (_ == "rect" || _ == "circle" || _ == "line" || (_ == "path" && (typeof d === 'string')) ){
|
|
shape = _;
|
|
path = d;
|
|
}
|
|
return legend;
|
|
};
|
|
|
|
legend.shapeWidth = function(_) {
|
|
if (!arguments.length) return shapeWidth;
|
|
shapeWidth = +_;
|
|
return legend;
|
|
};
|
|
|
|
legend.shapeHeight = function(_) {
|
|
if (!arguments.length) return shapeHeight;
|
|
shapeHeight = +_;
|
|
return legend;
|
|
};
|
|
|
|
legend.shapeRadius = function(_) {
|
|
if (!arguments.length) return shapeRadius;
|
|
shapeRadius = +_;
|
|
return legend;
|
|
};
|
|
|
|
legend.shapePadding = function(_) {
|
|
if (!arguments.length) return shapePadding;
|
|
shapePadding = +_;
|
|
return legend;
|
|
};
|
|
|
|
legend.labels = function(_) {
|
|
if (!arguments.length) return labels;
|
|
labels = _;
|
|
return legend;
|
|
};
|
|
|
|
legend.labelAlign = function(_) {
|
|
if (!arguments.length) return labelAlign;
|
|
if (_ == "start" || _ == "end" || _ == "middle") {
|
|
labelAlign = _;
|
|
}
|
|
return legend;
|
|
};
|
|
|
|
legend.labelFormat = function(_) {
|
|
if (!arguments.length) return labelFormat;
|
|
labelFormat = _;
|
|
return legend;
|
|
};
|
|
|
|
legend.labelOffset = function(_) {
|
|
if (!arguments.length) return labelOffset;
|
|
labelOffset = +_;
|
|
return legend;
|
|
};
|
|
|
|
legend.labelDelimiter = function(_) {
|
|
if (!arguments.length) return labelDelimiter;
|
|
labelDelimiter = _;
|
|
return legend;
|
|
};
|
|
|
|
legend.useClass = function(_) {
|
|
if (!arguments.length) return useClass;
|
|
if (_ === true || _ === false){
|
|
useClass = _;
|
|
}
|
|
return legend;
|
|
};
|
|
|
|
legend.orient = function(_){
|
|
if (!arguments.length) return orient;
|
|
_ = _.toLowerCase();
|
|
if (_ == "horizontal" || _ == "vertical") {
|
|
orient = _;
|
|
}
|
|
return legend;
|
|
};
|
|
|
|
legend.ascending = function(_) {
|
|
if (!arguments.length) return ascending;
|
|
ascending = !!_;
|
|
return legend;
|
|
};
|
|
|
|
legend.classPrefix = function(_) {
|
|
if (!arguments.length) return classPrefix;
|
|
classPrefix = _;
|
|
return legend;
|
|
};
|
|
|
|
legend.title = function(_) {
|
|
if (!arguments.length) return title;
|
|
title = _;
|
|
return legend;
|
|
};
|
|
|
|
d3.rebind(legend, legendDispatcher, "on");
|
|
|
|
return legend;
|
|
|
|
};
|
|
|