使用嵌套json数据的d3热图:如何创建网格

时间:2017-10-24 17:31:08

标签: javascript json d3.js

请参阅此示例:http://bl.ocks.org/tjdecke/5558084

我想创建一个52行和7列的热图。 52行代表一年中的52周,7列代表一周中的7天。

使用这样的数据集:(在下面发布缩写版本)。 “天”表示一周中的7天,里面的数字表示一天内的活动数量。 “总数”表示一周内的活动总数。 “周”似乎是各种各样的时间戳。

但是,我很难弄清楚如何创建网格,因为示例数据集使用带有7个值的d.day和带有24个值的d.hour来创建网格。具体来说,我应该如何处理days数组?

我不知道如何处理json值,例如,如何定义我的变量以使用此数据集。

[
  {
    "days": [
      0,
      0,
      0,
      0,
      0,
      1,
      0
    ],
    "total": 1,
    "week": 1457827200
  },
  {
    "days": [
      0,
      0,
      0,
      1,
      0,
      3,
      1
    ],
    "total": 5,
    "week": 1458432000
  },
  {
    "days": [
      1,
      0,
      0,
      1,
      5,
      0,
      1
    ],
    "total": 8,
    "week": 1459036800
  },
  {
    "days": [
      0,
      0,
      0,
      2,
      0,
      1,
      1
    ],
    "total": 4,
    "week": 1459641600
  },
  {
    "days": [
      0,
      1,
      3,
      0,
      2,
      0,
      0
    ],
    "total": 6,
    "week": 1460246400
  },
  {
    "days": [
      0,
      1,
      1,
      2,
      2,
      0,
      0
    ],
    "total": 6,
    "week": 1460851200
  },
  {
    "days": [
      1,
      0,
      3,
      0,
      2,
      1,
      0
    ],
    "total": 7,
    "week": 1461456000
  },
  {
    "days": [
      0,
      0,
      0,
      0,
      0,
      0,
      0
    ],
    "total": 0,
    "week": 1462060800
  }
  ]

    d3.json("/data/frequency.json", function (error, data) {

       // NOT SURE, PROBABLY WRONG
      data.forEach(function(d) {
        ddays = +d.days;
        total = +d.total;
        week = +d.week;
      });


      // define range!!!
      var x = d3.scaleLinear().domain([0, data.length]).range([0, width]);

      //52 weeks
      var y = d3.scaleLinear()
      .domain([0, 52])
      .rangeRound([height, 0]);

      // Generate rectangle for each json object
      var rectangles = svg.selectAll('rect')
      .data(data)
      .enter()
      .append('rect')
      .attr("x", function(d, index) {
        return x(index); }) //WRONG!!
      .attr("y", function(d, index) {
        return y; }) // WRONG!!
      .attr("width", gridSize)
      .attr("height", gridSize)
      .style("fill", 'black')
      .attr("class", "bordered");

1 个答案:

答案 0 :(得分:1)

使用嵌套数据,您可以先为每个对象附加组元素,以便每周在网格中创建一个“行”,根据其索引得到y坐标。

然后对于每一行,根据对象中的days数组追加rects。

诀窍是做两个data()连接,第二个连接从已经连接的数据中访问days数组。

例如:

     let data = [
  {
    "days": [
      0,
      0,
      0,
      0,
      0,
      1,
      0
    ],
    "total": 1,
    "week": 1457827200
  },
  {
    "days": [
      0,
      0,
      0,
      1,
      0,
      3,
      1
    ],
    "total": 5,
    "week": 1458432000
  },
  {
    "days": [
      1,
      0,
      0,
      1,
      5,
      0,
      1
    ],
    "total": 8,
    "week": 1459036800
  },
  {
    "days": [
      0,
      0,
      0,
      2,
      0,
      1,
      1
    ],
    "total": 4,
    "week": 1459641600
  },
  {
    "days": [
      0,
      1,
      3,
      0,
      2,
      0,
      0
    ],
    "total": 6,
    "week": 1460246400
  },
  {
    "days": [
      0,
      1,
      1,
      2,
      2,
      0,
      0
    ],
    "total": 6,
    "week": 1460851200
  },
  {
    "days": [
      1,
      0,
      3,
      0,
      2,
      1,
      0
    ],
    "total": 7,
    "week": 1461456000
  },
  {
    "days": [
      0,
      0,
      0,
      0,
      0,
      0,
      0
    ],
    "total": 0,
    "week": 1462060800
  }
  ]
 
			let gridSize = 20;
      let width = (gridSize + 1) * 7; 
    	let height = (gridSize + 1) * data.length;
    	
      // define range!!!
      var x = d3.scaleLinear()
      .domain([0, 7])
      .range([0, width]);

      //52 weeks
      var y = d3.scaleLinear()
      .domain([0, data.length])
      .rangeRound([height, 0]);
    
    	let svg = d3.select("body").append("svg")
      	.attr("width", width)
      .attr("height", height)

      // Generate rows for each json object
      var rows = svg.selectAll('.row')
      .data(data)
      .enter()
      .append('g')
      .attr("transform", function(d, i){ 
      	return "translate(0," + y(i) + ")"
      })
      
      // Generate rects for the array of days per object
      let box = rows.selectAll("rect")
      	.data(function(d){ return d.days })
      	.enter()
      	.append("rect")
				.attr("x", function(d, i) { return x(i); }) 
        .attr("width", gridSize)
        .attr("height", gridSize)
        .style("fill", 'black')
        .attr("class", "bordered");
<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
  </style>
</head>

<body>
</body>