代码之家  ›  专栏  ›  技术社区  ›  Antonio

如何调整d3中散点图矩阵的刷涂?

  •  8
  • Antonio  · 技术社区  · 8 年前

    我用的是Mike Bostok的 Block 用于刷涂散点图矩阵。

    我想刷一下 对角线图 使用不透明度数字的矩阵;画笔范围中间 opacity = 1 opacity value = low 在笔刷范围的侧面。

    此外,我在网上找不到任何提示 this question ,它执行相同的操作,但使用dc。js(借助pretransition属性)。

    这能在d3中实现吗?

    Running fiddle

    1 回复  |  直到 8 年前
        1
  •  7
  •   Mark    8 年前

    有趣的问题。

    下面是一段代码片段,它将通过 距离 从选择的中心。它在画笔端完成了这一操作,并进行了很好的过渡。以下是相关方法:

    function brushend(p) {
    
        // reset opacity
        svg.selectAll("circle").style('opacity', 1);
    
        // if no brush then bail
        if (brush.empty()) {
          svg.selectAll(".hidden").classed("hidden", false);
          return;
        }
    
        // some calculations
        var e = brush.extent(),
            xC = (e[1][0] + e[0][0]) / 2,
            yC = (e[1][1] + e[0][1]) / 2,
            // maxD is the maximum of the distance to the two edges
            maxD = Math.max( Math.sqrt((xC - e[0][0])**2), Math.sqrt ((yC - e[0][1])**2) );
    
        // those circles not hidden
        svg.selectAll("circle:not(.hidden)")
          .transition()
          .duration(1000)
          .style("opacity", function(d) {
            // distance from furthest edge
            var xD = Math.sqrt( (xC - d[p.x])**2 + (yC - d[p.y])**2 );
            // set opacity as percent of distance
            return (maxD - xD) / maxD;
        });
    
      }
    

    运行代码:

    <!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;
    }
    
    </style>
    <body>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script>
    
    var width = 960,
        size = 230,
        padding = 20;
    
    var x = d3.scale.linear()
        .range([padding / 2, size - padding / 2]);
    
    var y = d3.scale.linear()
        .range([size - padding / 2, padding / 2]);
    
    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .ticks(6);
    
    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        .ticks(6);
    
    var color = d3.scale.category10();
    
    d3.csv("https://gist.githubusercontent.com/mbostock/4063663/raw/13276d1a3d8e99e74c9fe33685da3afa6ed3a926/flowers.csv", function(error, data) {
      if (error) throw error;
    
      var domainByTrait = {},
          traits = d3.keys(data[0]).filter(function(d) { return d !== "species"; }),
          n = traits.length;
    
      traits.forEach(function(trait) {
        domainByTrait[trait] = d3.extent(data, function(d) { return d[trait]; });
      });
    
      xAxis.tickSize(size * n);
      yAxis.tickSize(-size * n);
    
      var brush = d3.svg.brush()
          .x(x)
          .y(y)
          .on("brushstart", brushstart)
          .on("brush", brushmove)
          .on("brushend", brushend);
    
      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(traits)
        .enter().append("g")
          .attr("class", "x axis")
          .attr("transform", function(d, i) { return "translate(" + (n - i - 1) * size + ",0)"; })
          .each(function(d) { x.domain(domainByTrait[d]); d3.select(this).call(xAxis); });
    
      svg.selectAll(".y.axis")
          .data(traits)
        .enter().append("g")
          .attr("class", "y axis")
          .attr("transform", function(d, i) { return "translate(0," + i * size + ")"; })
          .each(function(d) { y.domain(domainByTrait[d]); d3.select(this).call(yAxis); });
    
      var cell = svg.selectAll(".cell")
          .data(cross(traits, traits))
        .enter().append("g")
          .attr("class", "cell")
          .attr("transform", function(d) { return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")"; })
          .each(plot);
    
      // Titles for the diagonal.
      cell.filter(function(d) { return d.i === d.j; }).append("text")
          .attr("x", padding)
          .attr("y", padding)
          .attr("dy", ".71em")
          .text(function(d) { return d.x; });
    
      cell.call(brush);
    
      function plot(p) {
        var cell = d3.select(this);
    
        x.domain(domainByTrait[p.x]);
        y.domain(domainByTrait[p.y]);
    
        cell.append("rect")
            .attr("class", "frame")
            .attr("x", padding / 2)
            .attr("y", padding / 2)
            .attr("width", size - padding)
            .attr("height", size - padding);
    
        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", function(d) { return "#4682b4"; });
      }
    
      var brushCell;
    
      // Clear the previously-active brush, if any.
      function brushstart(p) {
        if (brushCell !== this) {
          d3.select(brushCell).call(brush.clear());
          x.domain(domainByTrait[p.x]);
          y.domain(domainByTrait[p.y]);
          brushCell = this;
        }
      }
    
      // Highlight the selected circles.
      function brushmove(p) {
        var e = brush.extent();
        svg.selectAll("circle").classed("hidden", function(d) {
          return e[0][0] > d[p.x] || d[p.x] > e[1][0]
              || e[0][1] > d[p.y] || d[p.y] > e[1][1];
        });
      }
    
      function brushend(p) {
        
        // reset opacity
        svg.selectAll("circle").style('opacity', 1);
        
        // if no brush then bail
        if (brush.empty()) {
          svg.selectAll(".hidden").classed("hidden", false);
          return;
        }
        
        // some calculations
        var e = brush.extent(),
            xC = (e[1][0] + e[0][0]) / 2,
            yC = (e[1][1] + e[0][1]) / 2,
            // maxD is the maximum of the distance to the two edges
            maxD = Math.max( Math.sqrt((xC - e[0][0])**2), Math.sqrt ((yC - e[0][1])**2) );
        
        // those circles not hidden
        svg.selectAll("circle:not(.hidden)")
          .transition()
          .duration(1000)
          .style("opacity", function(d) {
            // distance from furthest edge
            var xD = Math.sqrt( (xC - d[p.x])**2 + (yC - d[p.y])**2 );
            // set opacity as percent of distance
            return (maxD - xD) / maxD;
        });
        
      }
    });
    
    function cross(a, b) {
      var c = [], n = a.length, m = b.length, i, j;
      for (i = -1; ++i < n;) for (j = -1; ++j < m;) c.push({x: a[i], i: i, y: b[j], j: j});
      return c;
    }
    
    </script>