【问题标题】:How to create correlogram using D3 as in the example picture如何使用 D3 创建相关图,如示例图片所示
【发布时间】:2016-04-04 04:06:30
【问题描述】:

我正在尝试使用D3.js 使用一组数据创建一个相关图

我使用 R 创建相关矩阵,但为了可视化,我想使用 D3js 并创建一个图表,该图表显示图片中的相关矩阵。有人可以指导我吗?

【问题讨论】:

  • 您的数据的起点是什么?我熟悉R,所以我知道这是样本mtcars 数据集,您使用corrgram 包来绘制它。但是如果你用d3 做这个,你打算如何计算相关矩阵?

标签: javascript d3.js data-visualization


【解决方案1】:

有趣的问题,所以我解决了这个问题。使用mtcars 数据集并给定一个R 计算的相关矩阵,使用以下方法以CSV 格式输出:

write.csv(cor(mtcars), file="data.csv")

创建:

"","mpg","cyl","disp","hp","drat","wt","qsec","vs","am","gear","carb"
"mpg",1,-0.852161959426613,-0.847551379262479,-0.776168371826586,0.681171907806749,-0.867659376517228,0.418684033921778,0.664038919127593,0.599832429454648,0.480284757338842,-0.550925073902459
"cyl",-0.852161959426613,1,0.902032872146999,0.83244745272182,-0.69993811382877,0.782495794463241,-0.591242073768869,-0.810811796083005,-0.522607046900675,-0.492686599389471,0.526988293749643

您可以使用d3 复制您的情节:

d3.csv("data.csv", function(error, rows) {

  // read in the CSV file and put the data in a d3 format or an array of objects
  var data = [];
  rows.forEach(function(d) {
    var x = d[""]; // x represent the column name
    delete d[""];
    for (prop in d) {
      var y = prop, // y is this row name
        value = d[prop]; // correlation value
      data.push({
        x: x,
        y: y,
        value: +value
      });
    }
  });

  // standard d3 plot setup
  var margin = {
      top: 25,
      right: 80,
      bottom: 25,
      left: 25
    },
    width = 500 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom,
    domain = d3.set(data.map(function(d) { // our domain is just the column names
      return d.x
    })).values(),
    num = Math.sqrt(data.length), // how many rows and columns
    color = d3.scale.linear() // our color scale from red to white to blue
      .domain([-1, 0, 1])
      .range(["#B22222", "#fff", "#000080"]);

  // set-up x and y scale
  var x = d3.scale
    .ordinal()
    .rangePoints([0, width])
    .domain(domain),
  y = d3.scale
    .ordinal()
    .rangePoints([0, height])
    .domain(domain),
  xSpace = x.range()[1] - x.range()[0], // this is the space of each grid space
  ySpace = y.range()[1] - y.range()[0];

  var svg = d3.select("body")
    .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 + ")");

  // bind our data for each grid space
  var cor = svg.selectAll(".cor")
    .data(data)
    .enter()
    .append("g")
    .attr("class", "cor")
    .attr("transform", function(d) {
      return "translate(" + x(d.x) + "," + y(d.y) + ")";
    });

  // outer rectangle on each grid space
  cor.append("rect")
    .attr("width", xSpace)
    .attr("height", ySpace)
    .attr("x", -xSpace / 2)
    .attr("y", -ySpace / 2)

  // filter out below the diagonal
  cor.filter(function(d){
      var ypos = domain.indexOf(d.y);
      var xpos = domain.indexOf(d.x);
      for (var i = (ypos + 1); i < num; i++){
        if (i === xpos) return false;
      }
      return true;
    })
    // append a text
    .append("text")
    .attr("y", 5)
    .text(function(d) {
      if (d.x === d.y) {
        return d.x;
      } else {
        return d.value.toFixed(2);
      }
    })
    // color it
    .style("fill", function(d){
      if (d.value === 1) {
        return "#000";
      } else {
        return color(d.value);
      }
    });

    // filter above the diagonal
    cor.filter(function(d){
      var ypos = domain.indexOf(d.y);
      var xpos = domain.indexOf(d.x);
      for (var i = (ypos + 1); i < num; i++){
        if (i === xpos) return true;
      }
      return false;
    })
    // add a circle
    .append("circle")
    .attr("r", function(d){
      return (width / (num * 2)) * (Math.abs(d.value) + 0.1);
    })
    .style("fill", function(d){
      if (d.value === 1) {
        return "#000";
      } else {
        return color(d.value);
      }
    });

  // build the "yAxis" color scale
  // its a series of rects colored correctly
  // to produce a smooth gradient
  var aS = d3.scale
    .linear()
    .range([-margin.top + 5, height + margin.bottom - 5])
    .domain([1, -1]);

  var yA = d3.svg.axis()
    .orient("right")
    .scale(aS)
    .tickPadding(7);

  var aG = svg.append("g")
    .attr("class", "y axis")
    .call(yA)
    .attr("transform", "translate(" + (width + margin.right / 2) + " ,0)")

  var iR = d3.range(-1, 1.01, 0.01);
  var h = height / iR.length + 3;
  iR.forEach(function(d){
    aG.append('rect')
      .style('fill',color(d))
      .style('stroke-width', 0)
      .style('stoke', 'none')
      .attr('height', h)
      .attr('width', 10)
      .attr('x', 0)
      .attr('y', aS(d))
   });
});

结果如下:

Full working code.

我们可以使用 d3 v4 here's the updated coded3 changes' log

【讨论】:

  • 感谢 @ruddra 在此用例场景上花费宝贵的时间。它真的会帮助我。
  • @ralfbecher,只需按值缩放圆圈。 return (width / (num * 2)) * (Math.abs(d.value) + 0.1); 找到了一个适合网格的半径,按从零略微移动的值对其进行缩放。上面更新了代码。
  • @Mark 对此非常感谢,我已经尝试使用 v4 和 d3 guidence 以及你的代码来做到这一点;)它已经完成了 xD working code snippet d3 v4 但它可能需要一些关于到网格边距或类似的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多