简体   繁体   English

在矩阵散点图d3.js v4中应用缩放

[英]Applying zoom in matrix scatterplot d3.js v4

Here is a plunkr of a matrix scatterplot in d3 V4 http://plnkr.co/edit/7meh4sMhxItcQtCaAtZP?p=preview (It may take some time to load and display) 这是d3 V4中的矩阵散点图的插件, http ://plnkr.co/edit/7meh4sMhxItcQtCaAtZP?p = preview(加载和显示可能需要一些时间)

I am looking forward to zoom the plot in order to see the cluttered points in a convenient way. 我希望缩放该图,以便以方便的方式查看混乱的点。 I have used d3.zoom() to rescale the axis but the circles are not being plotted accordingly. 我已使用d3.zoom()重新缩放轴,但未相应绘制圆。

Here is the problem description: Initially, all the axis are set with different ranges (like top y-axis is having range from 4.5-7.5 , below that y-axis range is from 2.0-4.0 .. ) Now after zooming it, (ie when scrolling mouse over the circles), all the axis are set in the same ranges that leads to all circles oriented diagonally. 这里是问题的描述:最初,所有轴都设置了不同的范围(例如顶部y轴的范围是4.5-7.5,低于该y轴的范围是2.0-4.0 ..)现在将其缩放后,(例如,将鼠标滚动到圆圈上时),所有轴都设置在相同范围内,从而导致所有圆圈对角线定向。

Is there a workaround for that so that we can zoom the axis accordingly and visualize it nicely !! 有没有解决方法,以便我们可以相应地缩放轴并将其可视化!

Thanks. 谢谢。 Any help would highly appreciated. 任何帮助将不胜感激。

<!DOCTYPE html>
<meta charset="utf-8">
<style>

    svg {
        font: 10px sans-serif;
        padding: 10px;
    }

    .axis,
    .frame {
        shape-rendering: crispEdges;
    }

    .axis line {
        stroke: #ddd;
    }

    .axis path {
        display: none;
    }

    .cell text {
        font-weight: bold;
        text-transform: capitalize;
    }

    .frame {
        fill: none;
        stroke: #aaa;
    }

    circle {
        fill-opacity: .7;
    }

    circle.hidden {
        fill: #ccc !important;
    }

    .extent {
        fill: #000;
        fill-opacity: .125;
        stroke: #fff;
    }

    div.tooltip {
        position: absolute;
        text-align: center;
        width: 100px;
        height: 80px;
        padding: 2px;
        font: 12px sans-serif;
        background: lightsteelblue;
        border: 0px;
        border-radius: 8px;
        pointer-events: none;
    }

</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>


<script>

  var tooltipDiv;
    d3.helper = {};

   var zoomable = true;
   var new_xScale;
   var new_yScale;


    d3.helper.tooltip = function (param1, param2) {

        var bodyNode = d3.select('body').node();


        function tooltip(selection) {
            selection.on('mouseover.tooltip', function (point) {

                // Clean up lost tooltips
                d3.select('body').selectAll('div.tooltip').remove();
                // Append tooltip
                tooltipDiv = d3.select('body')
                    .append('div')
                    .attr('class', 'tooltip');
                var absoluteMousePos = d3.mouse(bodyNode);
                //console.log('absoluteMousePos', absoluteMousePos);
                tooltipDiv
                    .style('left', (absoluteMousePos[0] + 10) + 'px')
                    .style('top', (absoluteMousePos[1] - 30) + 'px');

                var line = '';
                //var temp_key = d3.keys(point);
                var temp_key = [param1, param2];

               // _.each(d3.keys(point), function (key, index) {
                temp_key.forEach(function (key, index) {


                    if (index != temp_key.length - 1) {

                        line += key + ': ' + point[key] + '</br>';
                    } else {


                        line += key + ': ' + point[key];
                    }
                });
                tooltipDiv.html(line);
            })
                .on('mousemove.tooltip', function () {
                    // Move tooltip
                    var absoluteMousePos = d3.mouse(bodyNode);
                    tooltipDiv
                        .style("left", (absoluteMousePos[0] + 10) + 'px')
                        .style("top", absoluteMousePos[1] < 80 ? absoluteMousePos[1] + 10 :(absoluteMousePos[1] - 70) + 'px');
                })
                .on('mouseout.tooltip', function () {
                    // Remove tooltip
                    tooltipDiv.remove();
                });


        }

        tooltip.attr = function (_x) {
            if (!arguments.length) return attrs;
            attrs = _x;
            return this;
        };

        tooltip.style = function (_x) {
            if (!arguments.length) return styles;
            styles = _x;
            return this;
        };

        return tooltip;
    };

    var width = 500,
        size = 150,
        padding = 20;

    var x = d3.scaleLinear().rangeRound([padding / 2, size - padding / 2]);
    var y = d3.scaleLinear().rangeRound([size - padding / 2, padding / 2]);

    var xAxis = d3.axisBottom()
        .scale(x)
        .ticks(7);

    var yAxis = d3.axisLeft()
        .scale(y)
        .ticks(7);

    var color = d3.scaleOrdinal(d3.schemeCategory10);

    d3.json("flowers.json", function (data) {

        var attr2Domain = {},

          attrs= ['sepal length', 'sepal width', 'petal length','petal width']  
          n = attrs.length;

        attrs.forEach(function (attr) {
            attr2Domain[attr] = d3.extent(data, function (ele) {
                return ele[attr];
            });
        });

        xAxis.tickSize(size * n);
    yAxis.tickSize(-size * n);


        var svg = d3.select("body")
            .append("svg")
            .attr("width", size * n + padding)
            .attr("height", size * n + padding)
            .append("g")
            .attr("transform", "translate(" + padding + "," + padding / 2 + ")");

        svg.selectAll(".x.axis")
            .data(attrs)
            .enter().append("g")
            .attr("class", "x axis")
            .attr("transform", function (d, i) {
                return "translate(" + (n - i - 1) * size + ",0)";
            })
            .each(function (d) {
                x.domain(attr2Domain[d]);
                d3.select(this).call(xAxis);
            });

        svg.selectAll(".y.axis")
            .data(attrs)
            .enter().append("g")
            .attr("class", "y axis")
            .attr("transform", function (d, i) {
                return "translate(0," + i * size + ")";
            })
            .each(function (d) {
                y.domain(attr2Domain[d]);
                d3.select(this).call(yAxis);
            });

        var cell = svg.selectAll(".cell")
            .data(cross(attrs, attrs))
            .enter()
            .append("g")
            .attr("class", "cell")
            .attr("classx", function(d){ return d.x; })
            .attr("classy", function(d){ return d.y; })
            .attr("transform", function (d) { 
                return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")";
            });

        // Titles for the diagonal.
        cell.filter(function (d) {
            return d.i === d.j;
        })
            .append("text")
            .attr("x", padding)
            .attr("y", padding)
            .attr("dy", ".71em")
            .style("fill", "black")
            .text(function (d) {
                return d.x;
            });


        cell.each(plot);

        // plot each cell
        function plot(p) {
             cell = d3.select(this);

            x.domain(attr2Domain[p.x]);
            y.domain(attr2Domain[p.y]);

            cell.append("rect")
                .attr("class", "frame")
                .attr("x", padding / 2)
                .attr("y", padding / 2)
                .attr("width", size - padding)
                .style("pointer-events", "none")
                .attr("height", size - padding);

             var  circles = cell.selectAll("circle")
                .data(data)
                .enter().append("circle")
                .attr("cx", function (d) { 
                    return x(d[p.x]);
                })
                .attr("cy", function (d) {
                    return y(d[p.y]);
                })
                .attr("r", 4)

                //.style("fill", "green");
                .style("fill", function (d) {
                  return color(d.species);
                });




            circles.on('mousemove', function(){

            var param1 = d3.select(this.parentNode).attr("classx"); 
            var param2 = d3.select(this.parentNode).attr("classy");
            circles.call(d3.helper.tooltip(param1, param2));

            }); 


        }

//---------------------------------------------  applying zoom----------   

   applyZoom(); 

  function applyZoom() {
    if (zoomable) {
      var zoom = d3.zoom()
        .on("zoom", zoomed);

      svg.call(zoom).on("dblclick.zoom", null);
    }
  }


   function zoomed() {
   console.log('zoomed');

     new_xScale = d3.event.transform.rescaleX(x);
     new_yScale = d3.event.transform.rescaleY(y);

    console.log("new_xScale", x);

      svg.selectAll(".x.axis")
      .each(function (d) {
                x.domain(attr2Domain[d]);
                d3.select(this).call(xAxis.scale(new_xScale));
            });



       svg.selectAll(".y.axis")
      .each(function (d) {
                y.domain(attr2Domain[d]);
                d3.select(this).call(yAxis.scale(new_yScale));
            });

         cell.each(plotly);


}



 function plotly(p) {

      console.log("plotly", p);
        //return x(d[p.x])

        svg.selectAll("circle")
       .attr("cx", function (d) {
                    return new_xScale(d[p.x]);
                })
         .attr("cy", function (d) {
                   return new_yScale(d[p.y]);
                   });

        }



});


     function cross(a, b) {
        var c = [], n = a.length, m = b.length, i, j;
        for (i = 0; i < n; i++) {
            for (j = 0; j < m; j++) {
                c.push({x: a[i], i: i, y: b[j], j: j});
            }
        }
        return c;
    }

   </script>  

I think move'new_xScale = d3.event.transform.rescaleX(x)' after 'x.domain(attr2Domain[d])' inside each function should work. 我认为在每个函数内的“ x.domain(attr2Domain [d])”之后应该移动“ new_xScale = d3.event.transform.rescaleX(x)”。 The same as y. 与y相同。

Thanks 谢谢

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM