Skip to content

Commit 402aafe

Browse files
authored
fix #278; robust log domain (#279)
1 parent 21664a9 commit 402aafe

File tree

5 files changed

+104
-6
lines changed

5 files changed

+104
-6
lines changed

src/defined.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export function positive(x) {
2727
return x > 0 ? x : NaN;
2828
}
2929

30+
export function negative(x) {
31+
return x < 0 ? x : NaN;
32+
}
33+
3034
export function firstof(...values) {
3135
for (const v of values) {
3236
if (v !== undefined) {

src/scales/quantitative.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import {
5050
} from "d3";
5151
import {scaleDiverging, scaleLinear, scaleLog, scalePow, scaleSymlog} from "d3";
5252
import {registry, radius, color} from "./index.js";
53-
import {positive} from "../defined.js";
53+
import {positive, negative} from "../defined.js";
5454

5555
const constant = x => () => x;
5656
const flip = i => t => i(1 - t);
@@ -179,8 +179,8 @@ export function ScalePow(key, channels, {exponent = 1, ...options}) {
179179
return ScaleQ(key, scalePow().exponent(exponent), channels, options);
180180
}
181181

182-
export function ScaleLog(key, channels, {base = 10, ...options}) {
183-
return ScaleQ(key, scaleLog().base(base), channels, options);
182+
export function ScaleLog(key, channels, {base = 10, domain = inferLogDomain(channels), ...options}) {
183+
return ScaleQ(key, scaleLog().base(base), channels, {domain, ...options});
184184
}
185185

186186
export function ScaleSymlog(key, channels, {constant = 1, ...options}) {
@@ -215,10 +215,10 @@ export function ScaleDiverging(key, channels, {
215215
return {type: "quantitative", invert, domain, scale};
216216
}
217217

218-
function inferDomain(channels) {
218+
function inferDomain(channels, f) {
219219
return [
220-
min(channels, ({value}) => value === undefined ? value : min(value)),
221-
max(channels, ({value}) => value === undefined ? value : max(value))
220+
min(channels, ({value}) => value === undefined ? value : min(value, f)),
221+
max(channels, ({value}) => value === undefined ? value : max(value, f))
222222
];
223223
}
224224

@@ -232,3 +232,16 @@ function inferRadialRange(channels, domain) {
232232
const h25 = quantile(channels, 0.5, ({value}) => value === undefined ? NaN : quantile(value, 0.25, positive));
233233
return domain.map(d => 3 * Math.sqrt(d / h25));
234234
}
235+
236+
function inferLogDomain(channels) {
237+
for (const {value} of channels) {
238+
if (value !== undefined) {
239+
for (let v of value) {
240+
v = +v;
241+
if (v > 0) return inferDomain(channels, positive);
242+
if (v < 0) return inferDomain(channels, negative);
243+
}
244+
}
245+
}
246+
return [1, 10];
247+
}

test/output/logDegenerate.svg

Lines changed: 68 additions & 0 deletions
Loading

test/plots/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export {default as letterFrequencyBar} from "./letter-frequency-bar.js";
3535
export {default as letterFrequencyColumn} from "./letter-frequency-column.js";
3636
export {default as letterFrequencyDot} from "./letter-frequency-dot.js";
3737
export {default as letterFrequencyLollipop} from "./letter-frequency-lollipop.js";
38+
export {default as logDegenerate} from "./log-degenerate.js";
3839
export {default as metroInequality} from "./metro-inequality.js";
3940
export {default as metroInequalityChange} from "./metro-inequality-change.js";
4041
export {default as metroUnemployment} from "./metro-unemployment.js";

test/plots/log-degenerate.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as Plot from "@observablehq/plot";
2+
3+
export default async function() {
4+
return Plot.plot({
5+
x: {
6+
type: "log"
7+
},
8+
marks: [
9+
Plot.dotX([0, 0.1, 1, 2, 10])
10+
]
11+
});
12+
}

0 commit comments

Comments
 (0)