自定义工具提示D3.js

时间:2019-11-18 22:57:10

标签: javascript d3.js

我正在使用以下代码创建小提琴图。我正在使用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;
    };
}

在此先感谢您的提示和指导。

0 个答案:

没有答案