Commit 113032bc authored by Mike Bostock's avatar Mike Bostock
Browse files

Restrict implicit domains to explicit ranges.

When an ordinal scale’s range is explicitly defined as an array of values, we
can build the domain implicitly by progressively assigning values from the
range; this is commonly done with color palettes, for example.

However, when an ordinal scale’s range is rather implied by chopping a
continuous range into a series of points or bands, then the domain must be
specified explicitly: for the scale to be consistent, we need to know the
cardinality of the domain to compute the implied range values.

Thus, it only makes sense to extend the domain implicitly when the range is
specified explicitly. Fixes #1536 #1535.
parent 9ca071ee
......@@ -7082,7 +7082,7 @@ d3 = function() {
function d3_scale_ordinal(domain, ranger) {
var index, range, rangeBand;
function scale(x) {
return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length];
return range[((index.get(x) || ranger.t === "range" && index.set(x, domain.push(x))) - 1) % range.length];
}
function steps(start, step) {
return d3.range(domain.length).map(function(i) {
......
This diff is collapsed.
......@@ -12,7 +12,7 @@ function d3_scale_ordinal(domain, ranger) {
rangeBand;
function scale(x) {
return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length];
return range[((index.get(x) || ranger.t === "range" && index.set(x, domain.push(x))) - 1) % range.length];
}
function steps(start, step) {
......
......@@ -12,15 +12,6 @@ suite.addBatch({
"defaults to the empty array": function(ordinal) {
assert.isEmpty(ordinal().domain());
},
"new input values are added to the domain": function(ordinal) {
var x = ordinal().range(["foo", "bar"]);
assert.equal(x(0), "foo");
assert.deepEqual(x.domain(), ["0"]);
assert.equal(x(1), "bar");
assert.deepEqual(x.domain(), ["0", "1"]);
assert.equal(x(0), "foo");
assert.deepEqual(x.domain(), ["0", "1"]);
},
"setting the domain forgets previous values": function(ordinal) {
var x = ordinal().range(["foo", "bar"]);
assert.equal(x(1), "foo");
......@@ -37,22 +28,6 @@ suite.addBatch({
assert.equal(x({toString: function() { return "foo"; }}), 42);
assert.equal(x({toString: function() { return "bar"; }}), 43);
},
"orders domain values by the order in which they are seen": function(ordinal) {
var x = ordinal();
x("foo");
x("bar");
x("baz");
assert.deepEqual(x.domain(), ["foo", "bar", "baz"]);
x.domain(["baz", "bar"]);
x("foo");
assert.deepEqual(x.domain(), ["baz", "bar", "foo"]);
x.domain(["baz", "foo"]);
assert.deepEqual(x.domain(), ["baz", "foo"]);
x.domain([]);
x("foo");
x("bar");
assert.deepEqual(x.domain(), ["foo", "bar"]);
},
"does not coerce domain values to strings": function(ordinal) {
var x = ordinal().domain([0, 1]);
assert.deepEqual(x.domain(), [0, 1]);
......@@ -73,6 +48,31 @@ suite.addBatch({
assert.isEmpty(x.range());
assert.isUndefined(x(0));
},
"new input values are added to the domain": function(ordinal) {
var x = ordinal().range(["foo", "bar"]);
assert.equal(x(0), "foo");
assert.deepEqual(x.domain(), ["0"]);
assert.equal(x(1), "bar");
assert.deepEqual(x.domain(), ["0", "1"]);
assert.equal(x(0), "foo");
assert.deepEqual(x.domain(), ["0", "1"]);
},
"orders domain values by the order in which they are seen": function(ordinal) {
var x = ordinal();
x("foo");
x("bar");
x("baz");
assert.deepEqual(x.domain(), ["foo", "bar", "baz"]);
x.domain(["baz", "bar"]);
x("foo");
assert.deepEqual(x.domain(), ["baz", "bar", "foo"]);
x.domain(["baz", "foo"]);
assert.deepEqual(x.domain(), ["baz", "foo"]);
x.domain([]);
x("foo");
x("bar");
assert.deepEqual(x.domain(), ["foo", "bar"]);
},
"setting the range remembers previous values": function(ordinal) {
var x = ordinal();
assert.isUndefined(x(0));
......@@ -141,6 +141,17 @@ suite.addBatch({
assert.equal(x.rangeBand(), 0);
var x = ordinal().domain(["a", "b", "c"]).rangePoints([120, 0], 2);
assert.equal(x.rangeBand(), 0);
},
"returns undefined for values outside the domain": function(ordinal) {
var x = ordinal().domain(["a", "b", "c"]).rangePoints([0, 1]);
assert.isUndefined(x("d"));
assert.isUndefined(x("e"));
assert.isUndefined(x("f"));
},
"does not implicitly add values to the domain": function(ordinal) {
var x = ordinal().domain(["a", "b", "c"]).rangePoints([0, 1]);
x("d"), x("e");
assert.deepEqual(x.domain(), ["a", "b", "c"]);
}
},
......@@ -176,6 +187,17 @@ suite.addBatch({
var x = ordinal().domain(["a", "b", "c"]).rangeBands([120, 0], .2, 1);
assert.deepEqual(x.range(), [75, 50, 25]);
assert.equal(x.rangeBand(), 20);
},
"returns undefined for values outside the domain": function(ordinal) {
var x = ordinal().domain(["a", "b", "c"]).rangeBands([0, 1]);
assert.isUndefined(x("d"));
assert.isUndefined(x("e"));
assert.isUndefined(x("f"));
},
"does not implicitly add values to the domain": function(ordinal) {
var x = ordinal().domain(["a", "b", "c"]).rangeBands([0, 1]);
x("d"), x("e");
assert.deepEqual(x.domain(), ["a", "b", "c"]);
}
},
......@@ -203,6 +225,17 @@ suite.addBatch({
var x = ordinal().domain(["a", "b", "c"]).rangeRoundBands([120, 0], .2, 1);
assert.deepEqual(x.range(), [75, 50, 25]);
assert.equal(x.rangeBand(), 20);
},
"returns undefined for values outside the domain": function(ordinal) {
var x = ordinal().domain(["a", "b", "c"]).rangeRoundBands([0, 1]);
assert.isUndefined(x("d"));
assert.isUndefined(x("e"));
assert.isUndefined(x("f"));
},
"does not implicitly add values to the domain": function(ordinal) {
var x = ordinal().domain(["a", "b", "c"]).rangeRoundBands([0, 1]);
x("d"), x("e");
assert.deepEqual(x.domain(), ["a", "b", "c"]);
}
},
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment