Skip to content

Commit d419c44

Browse files
committed
normalize intervals
lists a few TODOs re: the default tick format: - we don't want decimal notation if the interval is specified as an integer - we don't want months to appear if the interval is specified as d3.utcYear - we don't want years to appear with commas (#768)
1 parent 2eeb68a commit d419c44

12 files changed

+225
-12
lines changed

src/axes.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {AxisX, AxisY} from "./axis.js";
33
import {isOrdinalScale, isTemporalScale, scaleOrder} from "./scales.js";
44
import {position, registry} from "./scales/index.js";
55
import {maybeInterval} from "./transforms/interval.js";
6+
import {formatDefault} from "./format.js";
67

78
export function Axes(
89
{x: xScale, y: yScale, fx: fxScale, fy: fyScale},
@@ -41,12 +42,18 @@ function autoAxisTicksK(scale, axis, k) {
4142
}
4243
}
4344

45+
// Scales defined with an interval default to regular ticks.
46+
// If the interval is specified as an integer, the tick format should not produce decimal dots.
4447
function tickInterval(scale, axis) {
4548
const interval = maybeInterval(scale.interval);
46-
if (interval != null) {
47-
const [min, max] = extent(scale.scale.domain());
48-
if (axis.ticks === undefined) axis.ticks = interval.range(interval.floor(min), interval.offset(interval.floor(max)));
49-
if (scale.type !== "point" && scale.type !== "band" && axis.tickFormat === undefined && typeof scale.interval === "number") axis.tickFormat = ",";
49+
if (interval !== undefined) {
50+
if (axis.ticks === undefined) {
51+
const [min, max] = extent(scale.scale.domain());
52+
axis.ticks = interval.range(interval.floor(min), interval.offset(interval.floor(max)));
53+
}
54+
if (axis.tickFormat === undefined) {
55+
axis.tickFormat = formatDefault;
56+
}
5057
}
5158
}
5259

src/scales.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ function Scale(key, channels = [], options = {}) {
143143
if (options.type === undefined
144144
&& options.domain === undefined
145145
&& options.range === undefined
146-
&& options.interval == null
146+
&& options.interval === undefined
147147
&& key !== "fx"
148148
&& key !== "fy"
149149
&& isOrdinalScale({type})) {

src/scales/ordinal.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function ScaleO(scale, channels, {
2828
if (typeof range === "function") range = range(domain);
2929
scale.range(range);
3030
}
31-
return {type, domain, range, scale, hint, interval};
31+
return {type, domain, range, scale, hint, interval: maybeInterval(interval)};
3232
}
3333

3434
export function ScaleOrdinal(key, channels, {

src/scales/quantitative.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
import {positive, negative, finite} from "../defined.js";
2727
import {arrayify, constant, order} from "../options.js";
2828
import {ordinalRange, quantitativeScheme} from "./schemes.js";
29+
import {maybeInterval} from "../transforms/interval.js";
2930
import {registry, radius, opacity, color, length} from "./index.js";
3031

3132
export const flip = i => t => i(1 - t);
@@ -106,7 +107,7 @@ export function ScaleQ(key, scale, channels, {
106107
if (nice) scale.nice(nice === true ? undefined : nice), domain = scale.domain();
107108
if (range !== undefined) scale.range(range);
108109
if (clamp) scale.clamp(clamp);
109-
return {type, domain, range, scale, interpolate, interval};
110+
return {type, domain, range, scale, interpolate, interval: maybeInterval(interval)};
110111
}
111112

112113
export function ScaleLinear(key, channels, options) {

test/output/integerInterval.svg

Lines changed: 62 additions & 0 deletions
Loading

test/output/yearlyRequestsLine.svg

Lines changed: 110 additions & 0 deletions
Loading

test/plots/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export {default as groupedRects} from "./grouped-rects.js";
7070
export {default as hadcrutWarmingStripes} from "./hadcrut-warming-stripes.js";
7171
export {default as highCardinalityOrdinal} from "./high-cardinality-ordinal.js";
7272
export {default as identityScale} from "./identity-scale.js";
73+
export {default as integerInterval} from "./integer-interval.js";
7374
export {default as ibmTrading} from "./ibm-trading.js";
7475
export {default as industryUnemployment} from "./industry-unemployment.js";
7576
export {default as industryUnemploymentShare} from "./industry-unemployment-share.js";
@@ -173,6 +174,7 @@ export {default as wordCloud} from "./word-cloud.js";
173174
export {default as wordLengthMobyDick} from "./word-length-moby-dick.js";
174175
export {default as yearlyRequests} from "./yearly-requests.js";
175176
export {default as yearlyRequestsDot} from "./yearly-requests-dot.js";
177+
export {default as yearlyRequestsLine} from "./yearly-requests-line.js";
176178

177179
export * from "./legend-color.js";
178180
export * from "./legend-opacity.js";

test/plots/integer-interval.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import * as Plot from "@observablehq/plot";
2+
3+
export default async function() {
4+
const requests = [[2,9],[3,17],[5,12]];
5+
return Plot.plot({
6+
// Since these numbers represent years, we want to format them without the comma
7+
// TODO: this should be automatic, even for a continuous scale
8+
x: {interval: 1, label: null, inset: 30},
9+
y: {label: null, zero: true},
10+
marks: [
11+
Plot.lineY(requests, {x: "0", y: "1"})
12+
]
13+
});
14+
}

test/plots/yearly-requests-dot.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import * as d3 from "d3";
22
import * as Plot from "@observablehq/plot";
33

44
export default async function() {
5-
const requests = [[new Date(2002, 0, 1), 9], [new Date(2003, 0, 1), 17], [new Date(2005, 0, 1), 5]];
5+
const requests = [[new Date(Date.UTC(2002, 0, 1)), 9], [new Date(Date.UTC(2003, 0, 1)), 17], [new Date(Date.UTC(2005, 0, 1)), 5]];
66
return Plot.plot({
7-
x: {type: "utc", interval: d3.utcYear, label: null, inset: 40, grid: true},
7+
// TODO: the default tickFormat could be inferred from the interval
8+
x: {type: "utc", interval: d3.utcYear, label: null, inset: 40, grid: true, tickFormat: "%Y"},
89
y: {label: null, zero: true},
910
marks: [
1011
Plot.ruleY([0]),

test/plots/yearly-requests-line.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import * as Plot from "@observablehq/plot";
2+
3+
export default async function() {
4+
const requests = [[2002,9],[2003,17],[2004,12],[2005,5],[2006,12],[2007,18],[2008,16],[2009,11],[2010,9],[2011,8],[2012,9],[2019,20]];
5+
return Plot.plot({
6+
// Since these numbers represent years, we want to format them without the comma
7+
// TODO: this should be automatic, even for a continuous scale
8+
x: {interval: 1, label: null, inset: 20, tickFormat: ""},
9+
y: {label: null, zero: true},
10+
marks: [
11+
Plot.lineY(requests, {x: "0", y: "1"})
12+
]
13+
});
14+
}

0 commit comments

Comments
 (0)