Skip to content

Commit afc9e38

Browse files
committed
rebase
1 parent c1ba415 commit afc9e38

File tree

2 files changed

+35
-3
lines changed

2 files changed

+35
-3
lines changed

src/mark.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function Channel(data, {scale, type, value}) {
6363
// This allows transforms to behave equivalently to channels.
6464
export function valueof(data, value, type) {
6565
const array = type === undefined ? Array : type;
66-
return typeof value === "string" ? array.from(data, field(value))
66+
return typeof value === "string" ? isColumnar(data) ? data.column(value) : array.from(data, field(value))
6767
: typeof value === "function" ? array.from(data, value)
6868
: typeof value === "number" || value instanceof Date ? array.from(data, constant(value))
6969
: value && typeof value.transform === "function" ? arrayify(value.transform(data), type)
@@ -133,7 +133,7 @@ export function keyword(input, name, allowed) {
133133
// the specified data is null or undefined, returns the value as-is.
134134
export function arrayify(data, type) {
135135
return data == null ? data : (type === undefined
136-
? (data instanceof Array || data instanceof TypedArray) ? data : Array.from(data)
136+
? (data instanceof Array || data instanceof TypedArray || isColumnar(data)) ? data : Array.from(data)
137137
: (data instanceof type ? data : type.from(data)));
138138
}
139139

@@ -180,7 +180,7 @@ export function titleGroup(L) {
180180

181181
// Returns a Uint32Array with elements [0, 1, 2, … data.length - 1].
182182
export function range(data) {
183-
return Uint32Array.from(data, indexOf);
183+
return Uint32Array.from(data.length ? {length: data.length} : data, indexOf);
184184
}
185185

186186
// Returns an array [values[index[0]], values[index[1]], …].
@@ -340,3 +340,7 @@ export function isTemporal(values) {
340340
return value instanceof Date;
341341
}
342342
}
343+
344+
function isColumnar(data) {
345+
return typeof data.column === "function";
346+
}

test/columnar-test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as Plot from "@observablehq/plot";
2+
import * as d3 from "d3";
3+
import tape from "tape-await";
4+
5+
tape("Plot uses the data.column accessor", test => {
6+
const columnChecks = [];
7+
const columnX = ["A", "B", "C", "D"];
8+
const columnY = [1, 1, 2];
9+
const data = {
10+
length: 5,
11+
column: function(field) {
12+
columnChecks.push(field);
13+
switch(field) {
14+
case "x": return columnX;
15+
case "y": return columnY;
16+
}
17+
},
18+
*[Symbol.iterator] () {
19+
/* eslint require-yield: 0 */
20+
throw new Error("The iterator should not be called");
21+
}
22+
};
23+
const A = Plot.dot(data, {x: "x", y: "y"}).initialize();
24+
test.deepEqual(A.index, d3.range(data.length));
25+
test.deepEqual(columnChecks, ["x", "y"]);
26+
test.strictEqual(A.channels.find(([c]) => c === "x")[1].value, columnX);
27+
test.strictEqual(A.channels.find(([c]) => c === "y")[1].value, columnY);
28+
});

0 commit comments

Comments
 (0)