You already have 4 different answers showing you how to convert an object with several properties in an array. However, as I said in my comment, this seems to be an XY problem to me, since what you really want at the end is just creating a heatmap.
Of course you can use any of the provided answers to create your data array in your inner selection. However, there are different ways to achieve the same result. This answer is just my two cents regarding your objective, not regarding what you actually asked.
You are correct when you said that data()
doesn't accept an object. In fact, data()
only accepts three things:
- An array;
- A function;
- Nothing.
That being said, we have to somehow convert that huge object in several objects, since each individual object represents a data point.
Preparing your data array
Suppose you have the following CSV (an 8 x 8 matrix of values). In this CSV, the first row, the header, is just the column number. All the values (from the second row on) go from 0 to 100:
1, 2, 3, 4, 5, 6, 7, 8
99, 01, 01, 56, 65, 34, 87, 65
76, 99, 73, 23, 54, 62, 12, 15
54, 77, 66, 23, 98, 76, 11, 12
13, 24, 56, 76, 88, 75, 43, 76
12, 33, 44, 52, 45, 87, 65, 67
88, 76, 67, 87, 54, 34, 44, 45
12, 13, 24, 65, 45, 47, 76, 87
65, 43, 23, 42, 42, 34, 42, 17
With this CSV, you can create a data array in which each object contains the row number, the column number and the value. For instance, parsing the CSV to an array named rawData
, we can populate the final data array, named data
, like this:
rawData.forEach(function(d, i) {
Object.keys(d).forEach(function(e) {
data.push({
row: i,
column: e,
value: d[e]
})
})
});
Thus, you only need to access d.row
, d.column
and d.value
in your selection.
.attr("x", function(d) {
return xScale(d.column)
})
.attr("y", function(d) {
return xScale(d.row)
})
.attr("fill", function(d) {
return color(d.value)
})
Here is a very simple demo:
var svg = d3.select("svg");
var rawData = d3.csvParse(d3.select("#csv").text())
var color = d3.scaleLinear().domain([0, 100]).range(["maroon", "lawngreen"]);
var xScale = d3.scaleBand().domain(d3.range(1, 9, 1)).range([20, 180]);
var yScale = d3.scaleBand().domain(d3.range(1, 9, 1)).range([20, 180]);
var data = [];
rawData.forEach(function(d, i) {
Object.keys(d).forEach(function(e) {
data.push({
row: i,
column: e,
value: d[e]
})
})
});
var rects = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("width", xScale.bandwidth() - 2)
.attr("height", yScale.bandwidth() - 2)
.attr("x", function(d) {
return xScale(d.column)
})
.attr("y", function(d) {
return xScale(d.row)
})
.attr("fill", function(d) {
return color(d.value)
})
pre {
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="200" height="200"></svg>
<pre id="csv">1,2,3,4,5,6,7,8
99,01,01,56,65,34,87,65
76,99,73,23,54,62,12,15
54,77,66,23,98,76,11,12
13,24,56,76,88,75,43,76
12,33,44,52,45,87,65,67
88,76,67,87,54,34,44,45
12,13,24,65,45,47,76,87
65,43,23,42,42,34,42,17</pre>
Note that in this demo I'm using a <pre>
element to store the data, since I cannot use d3.csv
in a Stack snippet.
d3.csv
does.