Reputation: 481
I have made a violin plot in D3.js with the following code:
<script src="https://d3js.org/d3.v4.js"></script>`
<div id="power"></div>
<script>
var margin = {top: 120, right: 100, bottom: 80, left: 100},
width = 2600 - margin.left - margin.right,
height = 620 - margin.top - margin.bottom;
var svg = d3.select("#power")
.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 + ")");
// Read the data and compute summary statistics for each
d3.csv("static/csv/violinsummary.csv", function (data) {
// Show the X scale
var x = d3.scaleBand()
.range([0, width])
.domain(["2017-09", "2017-10", "2018-02", "2018-03"])
.paddingInner(0)
.paddingOuter(.5);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Show the Y scale
var y = d3.scaleLinear()
.domain([80, 105])
.range([height, 0]);
svg.append("g").call(d3.axisLeft(y));
// Features of density estimate
var kde = kernelDensityEstimator(kernelEpanechnikov(.2), y.ticks(50));
// Compute the binning for each group of the dataset
var sumstat = d3.nest()
.key(function (d) {
return d.DATE;
})
.rollup(function (d) { // For each key..
input = d.map(function (g) {
return g.Power;
});
density = kde(input); // And compute the binning on it.
return (density);
})
.entries(data);
var maxNum = 0;
for (i in sumstat) {
allBins = sumstat[i].value;
kdeValues = allBins.map(function (a) {
return a[1]
});
biggest = d3.max(kdeValues);
if (biggest > maxNum) {
maxNum = biggest
}
}
// The maximum width of a violin must be x.bandwidth = the width dedicated to a group
var xNum = d3.scaleLinear()
.range([0, x.bandwidth()])
.domain([-maxNum, maxNum]);
svg
.selectAll("myViolin")
.data(sumstat)
.enter() // So now we are working group per group
.append("g")
.attr("transform", function (d) {
return ("translate(" + x(d.key) + " ,0)")
}) // Translation on the right to be at the group position
.append("path")
.datum(function (d) {
return (d.value)
}) // So now we are working density per density
.style("opacity", .7)
.style("fill", "#317fc8")
.attr("d", d3.area()
.x0(function (d) {
return (xNum(-d[1]))
})
.x1(function (d) {
return (xNum(d[1]))
})
.y(function (d) {
return (y(d[0]))
})
.curve(d3.curveCatmullRom));
});
function kernelDensityEstimator(kernel, X) {
return function (V) {
return X.map(function (x) {
return [x, d3.mean(V, function (v) {
return kernel(x - v);
})];
});
}
}
function kernelEpanechnikov(k) {
return function (v) {
return Math.abs(v /= k) <= 1 ? 0.75 * (1 - v * v) / k : 0;
};
}
</script>
Data (violinsummary.csv):
Power,DATE
89.29,2017-09
89.9,2017-09
91.69,2017-09
89.23,2017-09
91.54,2017-09
88.49,2017-09
89.15,2017-09
90.85,2017-09
89.59,2017-09
93.38,2017-10
92.41,2017-10
90.65,2017-10
91.07,2017-10
90.13,2017-10
91.73,2017-10
91.09,2017-10
93.21,2017-10
91.62,2017-10
89.58,2017-10
90.59,2017-10
92.57,2017-10
89.99,2017-10
90.59,2017-10
88.12,2017-10
91.3,2017-10
89.59,2018-02
91.9,2018-02
87.83,2018-02
90.36,2018-02
91.38,2018-02
91.56,2018-02
91.89,2018-02
90.95,2018-02
90.15,2018-02
90.24,2018-02
94.04,2018-02
85.4,2018-02
88.47,2018-02
92.3,2018-02
92.46,2018-02
92.26,2018-02
88.78,2018-02
90.13,2018-03
89.95,2018-03
92.98,2018-03
91.94,2018-03
90.29,2018-03
91.2,2018-03
94.22,2018-03
90.71,2018-03
93.03,2018-03
91.89,2018-03
I am trying to make a tooltip for each violin that shows the median and mean upon hover. I cannot figure out how to make the tooltip show up.
I know I need to do something like this with mouseover and mouseout but I'm not sure...
var tooltip = d3.select('#power')
.append('div')
.attr('class', 'tooltip')
.style("opacity", 0);
Any tips/guidance would be very appreciated.
Upvotes: 0
Views: 278
Reputation: 4370
You can implement the tooltip functionality by following two steps.
Initialize the tooltip container which already you did I guess.
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
Change the visibility property of the tooltip in the mouseover
, mouseout
event of the element. In your case, it's myViolin
.on("mouseover", function() {
tooltip.style("display", null);
})
.on("mouseout", function() {
tooltip.style("display", "none");
})
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 15;
var yPosition = d3.mouse(this)[1] - 25;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.y);
});
Here is the implementation of tooltip jsFiddle
Hope it helps :)
Upvotes: 1