我正在使用以下代码创建小提琴图。我正在使用d3-tip创建我的工具提示(https://github.com/VACLab/d3-tip/blob/master/d3-tip.js)。工具提示适用于每个小提琴的悬停。但是,我无法弄清楚如何自定义工具提示中的内容。如您在定义工具提示时的代码中所见,我尝试使用 q1,q1,中位数:中位数,q3:q3,interQuantileRange:interQuantileRange,min:min,max,max 先前的指标功能。我希望每个小提琴的工具提示都具有这些值。例如,我在代码中绘制了每个小提琴的中线。我希望能够在工具提示中显示该中间线的值,以及q1,q3,interQuantileRange,最小值,最大值。
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
<div id="power"></div>
var margin = {top: 120, right: 100, bottom: 80, left: 100},
width = 2600 - margin.left - margin.right,
height = 620 - margin.top - margin.bottom;
// append the svg object to the body of the page
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() // nest function allows to group the calculation per level of a factor
.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 metrics = d3.nest()
.key(function (d) {
return d.DATE;
})
.rollup(function (d) {
q1 = d3.quantile(d.map(function (g) {
return g.Power;
}).sort(d3.ascending), .25);
median = d3.quantile(d.map(function (g) {
return g.Power;
}).sort(d3.ascending), .5);
q3 = d3.quantile(d.map(function (g) {
return g.Power;
}).sort(d3.ascending), .75);
interQuantileRange = q3 - q1;
min = q1 - 1.5 * interQuantileRange;
max = q3 + 1.5 * interQuantileRange;
return ({q1: q1, median: median, q3: q3, interQuantileRange: interQuantileRange, min: min, max: max})
})
.entries(data);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0]).html(function (d) {
return "<span style='margin-left: 2.5px;'><b>" + {q1: q1, median: median, q3: q3, interQuantileRange: interQuantileRange, min: min, max: max} + "</b></span><br>";
});
svg.call(tip);
// What is the biggest value that the density estimate reach?
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]);
// Add the shape to this svg!
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")
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.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)
);
// rectangle for the main box
var boxWidth = 50;
// Show the median
svg.selectAll("medianLines")
.data(metrics)
.enter()
.append("line")
.attr("x1", function (d) {
return (x(d.key) - boxWidth / 2)
})
.attr("x2", function (d) {
return (x(d.key) + boxWidth / 2)
})
.attr("y1", function (d) {
return (y(d.value.median))
})
.attr("y2", function (d) {
return (y(d.value.median))
})
.attr("stroke", "black")
.style("width", 80);
});
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;
};
}
在此先感谢您的提示和指导。