Skip to content

Commit fe09bb0

Browse files
committed
Allow objects as input to d3_dsv.format.
The previous implementation of format, which only supported arrays as input, is retained as d3_dsv.formatRows; for backwards-compatibility, d3_dsv.format allows both arrays and objects as input (to be removed in 4.0). This change makes format and formatRows symmetric with parse and parseRows, respectively. To compute the set of fields from all objects, two passes are required. Fields are listed in discovery order, so that in the common case where all fields are defined on all objects, the order of columns in the generated DSV will match the property iteration order of the first object. This supersedes d3#1106 and fixes d3#509; thank you to @smcgivern and @hammer for suggesting this feature.
1 parent 8b703e2 commit fe09bb0

5 files changed

Lines changed: 68 additions & 7 deletions

File tree

‎d3.js‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ d3 = function() {
10911091
return name == "transform" ? d3.interpolateTransform : d3.interpolate;
10921092
}
10931093
d3.interpolators = [ d3.interpolateObject, function(a, b) {
1094-
return b instanceof Array && d3.interpolateArray(a, b);
1094+
return Array.isArray(b) && d3.interpolateArray(a, b);
10951095
}, function(a, b) {
10961096
return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + "");
10971097
}, function(a, b) {
@@ -5416,6 +5416,22 @@ d3 = function() {
54165416
return rows;
54175417
};
54185418
dsv.format = function(rows) {
5419+
if (Array.isArray(rows[0])) return dsv.formatRows(rows);
5420+
var fieldSet = new d3_Set(), fields = [];
5421+
rows.forEach(function(row) {
5422+
for (var field in row) {
5423+
if (!fieldSet.has(field)) {
5424+
fields.push(fieldSet.add(field));
5425+
}
5426+
}
5427+
});
5428+
return [ fields ].concat(rows.map(function(row) {
5429+
return fields.map(function(field) {
5430+
return formatValue(row[field]);
5431+
}).join(delimiter);
5432+
})).join("\n");
5433+
};
5434+
dsv.formatRows = function(rows) {
54195435
return rows.map(formatRow).join("\n");
54205436
};
54215437
function formatRow(row) {

‎d3.min.js‎

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/core/interpolate.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ function d3_interpolateByName(name) {
254254

255255
d3.interpolators = [
256256
d3.interpolateObject,
257-
function(a, b) { return b instanceof Array && d3.interpolateArray(a, b); },
257+
function(a, b) { return Array.isArray(b) && d3.interpolateArray(a, b); },
258258
function(a, b) { return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + ""); },
259259
function(a, b) { return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Color) && d3.interpolateRgb(a, b); },
260260
function(a, b) { return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b); }

‎src/dsv/dsv.js‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,26 @@ function d3_dsv(delimiter, mimeType) {
9898
};
9999

100100
dsv.format = function(rows) {
101+
if (Array.isArray(rows[0])) return dsv.formatRows(rows); // deprecated; use formatRows
102+
var fieldSet = new d3_Set, fields = [];
103+
104+
// Compute unique fields in order of discovery.
105+
rows.forEach(function(row) {
106+
for (var field in row) {
107+
if (!fieldSet.has(field)) {
108+
fields.push(fieldSet.add(field));
109+
}
110+
}
111+
});
112+
113+
return [fields].concat(rows.map(function(row) {
114+
return fields.map(function(field) {
115+
return formatValue(row[field]);
116+
}).join(delimiter);
117+
})).join("\n");
118+
};
119+
120+
dsv.formatRows = function(rows) {
101121
return rows.map(formatRow).join("\n");
102122
};
103123

‎test/dsv/csv-test.js‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,31 @@ suite.addBatch({
160160
topic: function() {
161161
return d3.csv.format;
162162
},
163+
"takes an array of objects as input": function(format) {
164+
assert.equal(format([{a: 1, b: 2, c: 3}]), "a,b,c\n1,2,3");
165+
},
166+
"computes the union of all fields": function(format) {
167+
assert.equal(format([
168+
{a: 1},
169+
{a: 1, b: 2},
170+
{a: 1, b: 2, c: 3},
171+
{b: 1, c: 2},
172+
{c: 1}
173+
]), "a,b,c\n1,,\n1,2,\n1,2,3\n,1,2\n,,1");
174+
},
175+
"orders field by first-seen": function(format) {
176+
assert.equal(format([
177+
{a: 1, b: 2},
178+
{c: 3, b: 4},
179+
{c: 5, a: 1, b: 2}
180+
]), "a,b,c\n1,2,\n,4,3\n1,2,5");
181+
}
182+
},
183+
184+
"formatRows": {
185+
topic: function() {
186+
return d3.csv.formatRows;
187+
},
163188
"takes an array of arrays as input": function(format) {
164189
assert.equal(format([["a", "b", "c"], ["1", "2", "3"]]), "a,b,c\n1,2,3");
165190
},

0 commit comments

Comments
 (0)