I want to add a tooltip showing the exact values when hovering over one of the lines in the plot. How can I add a tooltip on each of the axis where the line touches the axis when that line is hovered? Any help would be highly appreciated. Ex. The attributes first, second, third and fourth should be shown when hovering over car
line. The same should happen for both test and train datasets.
var dataSet = [{
"type": "car",
"dataset": "test",
"first": 0.65,
"second": 0.34,
"third": 0.55,
"fourth": 0.39
},
{
"type": "car",
"dataset": "train",
"first": 0.59,
"second": 0.33,
"third": 0.50,
"fourth": 0.40
},
{
"type": "bicycle",
"dataset": "test",
"first": 200,
"second": 230,
"third": 250,
"fourth": 300
},
{
"type": "bicycle",
"dataset": "train",
"first": 200,
"second": 280,
"third": 225,
"fourth": 278
},
{
"type": "boat",
"dataset": "test",
"first": 320,
"second": 324,
"third": 532,
"fourth": 321
},
{
"type": "boat",
"dataset": "train",
"first": 128,
"second": 179,
"third": 166,
"fourth": 234
},
{
"type": "airplane",
"dataset": "test",
"first": 1500,
"second": 2000,
"third": 2321,
"fourth": 1793
},
{
"type": "airplane",
"dataset": "train",
"first": 1438,
"second": 2933,
"third": 2203,
"fourth": 2000
}
];
var processedData = [];
dataSet.forEach(function(d) {
var match = processedData.find(function(p) { return p.type === d.type; });
if(!match) {
match = {
type: d.type,
};
processedData.push(match);
}
var values = [d.first, d.second, d.third, d.fourth];
if(d.dataset === "train") {
match.train = values;
} else {
match.test = values;
}
});
processedData.forEach(function(d) {
// Normalise the values in the arrays
const min = Math.min(d3.min(d.train), d3.min(d.test));
const max = Math.max(d3.max(d.train), d3.max(d.test));
d.trainNormalised = d.train.map(function(v) {
return (v - min) / (max - min);
});
d.testNormalised = d.test.map(function(v) {
return (v - min) / (max - min);
});
});
var margin = {
top: 5,
right: 50,
bottom: 5,
left: 70
},
width = 600 - margin.left - margin.right,
height = 280 - margin.top - margin.bottom;
var categoryScale = d3.scale.ordinal()
.domain(processedData.map(function(d) { return d.type; }))
.rangePoints([0, height]);
var y = d3.scale.linear()
.domain([0, 1])
.range([height, 0]);
var x = d3.scale.ordinal()
.domain(d3.range(5))
.rangePoints([0, width]);
var line = d3.svg.line()
.defined(function(d) {
return !isNaN(d[1]);
});
// CREATE A COLOR SCALE
var color = d3.scale.ordinal()
.range(["#4683b8", "#79add2", "#a6c9de", "#cadbed", "#9d9bc4", "#bcbed9", "#dadaea", "#f6d2a8", "#f2b076", "#ef914e", "#d65e2a"])
var svg = d3.select("#parallel_coor")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
svg.selectAll(".dimension.axis")
.data([categoryScale, y, y, y, y])
.enter()
.append("g")
.attr("class", "dimension axis")
.attr("transform", function(d, i) {
return "translate(" + x(i) + ")";
})
.each(function(d) {
const yAxis = d3.svg.axis()
.scale(d)
.ticks([])
.orient("left");
d3.select(this).call(yAxis);
});
function parallel(data) {
// Draw one line group per type (car, boat)
// Each line group consists of a train and a test line;
var lineGroup = svg.append("g")
.selectAll(".lineGroup")
.data(data)
.enter()
.append("g")
.attr("class", "lineGroup")
.each(function(d) {
if(d.train)
d3.select(this).append("path")
.datum([d, "train"]);
if(d.test)
d3.select(this).append("path")
.datum(function(d) { return [d, "test"]; });
})
lineGroup
.attr("stroke", function(d) {
var company = d.type.slice(0, d.type.indexOf(' '));
return color(company);
})
.selectAll("path")
.attr("class", function(d) { return d[1]; })
.attr("d", draw);
lineGroup
.on("mouseover", function(d) {
// show train when click others
d3.select(this).classed("active", true);
lineGroup
.filter(function(e) { return e.type !== d.type; })
.style('opacity', 0.2);
})
.on("mouseout", function(d) {
d3.select(this).classed("active", false);
lineGroup.style('opacity', null);
});
function draw(d) {
var data = d[0], type = d[1];
var points = data[type + "Normalised"].map(function(v, i) {
return [x(i + 1), y(v)];
});
points.unshift([x(0), categoryScale(data.type)]);
return line(points);
}
}
parallel(processedData);
svg {
font: 12px sans-serif;
}
.lineGroup path {
fill: none;
}
.lineGroup.active .train {
visibility: visible;
}
.train {
visibility: hidden;
stroke-dasharray: 5 5;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div id="parallel_coor"></div>