D3 js工具提示小提琴图

时间:2019-11-14 23:45:56

标签: javascript d3.js

我在D3.js中用以下代码绘制了小提琴图:

    <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>

数据(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

我正在尝试为每把小提琴制作一个工具提示,以显示悬停时的中位数和均值。我不知道如何显示工具提示。

我知道我需要使用mouseover和mouseout来做类似的事情,但是我不确定...

 var tooltip = d3.select('#power')
      .append('div')
      .attr('class', 'tooltip')
      .style("opacity", 0);

任何提示/指导将不胜感激。

1 个答案:

答案 0 :(得分:0)

您可以按照以下两个步骤来实现工具提示功能。

步骤1:

初始化我已经猜过的工具提示容器。

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");

步骤2:

在元素的mouseovermouseout事件中更改工具提示的可见性属性。您的情况是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);
  });

这是工具提示jsFiddle

的实现

希望它会有所帮助:)

相关问题