Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function valueObject(channels, scales) {
for (const channelName in channels) {
const {scale: scaleName, value} = channels[channelName];
const scale = scales[scaleName];
values[channelName] = scale === undefined ? value : Array.from(value, scale);
values[channelName] = scale === undefined ? value : map(value, scale);
}
return values;
}
Expand Down
3 changes: 2 additions & 1 deletion src/legends/ramp.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {create, quantize, interpolateNumber, piecewise, format, scaleBand, scaleLinear, axisBottom} from "d3";
import {inferFontVariant} from "../axes.js";
import {map} from "../options.js";
import {interpolatePiecewise} from "../scales/quantitative.js";
import {applyInlineStyles, impliedString, maybeClassName} from "../style.js";

Expand Down Expand Up @@ -115,7 +116,7 @@ export function legendRamp(color, {
.attr("height", height - marginTop - marginBottom)
.attr("fill", d => d);

ticks = Array.from(thresholds, (_, i) => i);
ticks = map(thresholds, (_, i) => i);
tickFormat = i => thresholdFormat(thresholds[i], i);
}

Expand Down
19 changes: 12 additions & 7 deletions src/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ const objectToString = Object.prototype.toString;

// This allows transforms to behave equivalently to channels.
export function valueof(data, value, arrayType) {
const array = arrayType === undefined ? Array : arrayType;
const type = typeof value;
return type === "string" ? array.from(data, field(value))
: type === "function" ? array.from(data, value)
: type === "number" || value instanceof Date || type === "boolean" ? array.from(data, constant(value))
return type === "string" ? map(data, field(value), arrayType)
: type === "function" ? map(data, value, arrayType)
: type === "number" || value instanceof Date || type === "boolean" ? map(data, constant(value), arrayType)
: value && typeof value.transform === "function" ? arrayify(value.transform(data), arrayType)
: arrayify(value, arrayType); // preserve undefined type
}
Expand Down Expand Up @@ -85,6 +84,12 @@ export function map(values, f, type = Array) {
return values instanceof type ? values.map(f) : type.from(values, f);
}

// An optimization of type.from(values): if the given values are already an
// instanceof the desired array type, the faster values.slice method is used.
export function slice(values, type = Array) {
return values instanceof type ? values.slice() : type.from(values);
}

export function isTypedArray(values) {
return values instanceof TypedArray;
}
Expand Down Expand Up @@ -149,7 +154,7 @@ export function where(data, test) {

// Returns an array [values[index[0]], values[index[1]], …].
export function take(values, index) {
return Array.from(index, i => values[i]);
return map(index, i => values[i]);
}

// Based on InternMap (d3.group).
Expand Down Expand Up @@ -201,8 +206,8 @@ export function mid(x1, x2) {
const X1 = x1.transform(data);
const X2 = x2.transform(data);
return isTemporal(X1) || isTemporal(X2)
? Array.from(X1, (_, i) => new Date((+X1[i] + +X2[i]) / 2))
: Float64Array.from(X1, (_, i) => (+X1[i] + +X2[i]) / 2);
? map(X1, (_, i) => new Date((+X1[i] + +X2[i]) / 2))
: map(X1, (_, i) => (+X1[i] + +X2[i]) / 2, Float64Array);
},
label: x1.label
};
Expand Down
6 changes: 3 additions & 3 deletions src/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {Channel, channelObject, channelDomain, channelSort, valueObject} from ".
import {defined} from "./defined.js";
import {Dimensions} from "./dimensions.js";
import {Legends, exposeLegends} from "./legends.js";
import {arrayify, isOptions, isScaleOptions, keyword, range, second, where, yes} from "./options.js";
import {arrayify, isOptions, isScaleOptions, keyword, map, range, second, where, yes} from "./options.js";
import {Scales, ScaleFunctions, autoScaleRange, exposeScales} from "./scales.js";
import {registry as scaleRegistry} from "./scales/index.js";
import {applyInlineStyles, maybeClassName, maybeClip, styles} from "./style.js";
Expand Down Expand Up @@ -63,7 +63,7 @@ export function plot(options = {}) {
}
facetIndex = range(facetData);
facets = facetGroups(facetIndex, facetChannels);
facetsIndex = Array.from(facets, second);
facetsIndex = facets.map(second);
}
}

Expand Down Expand Up @@ -322,7 +322,7 @@ function applyScaleTransforms(channels, options) {
const {scale} = channel;
if (scale != null) {
const {percent, transform = percent ? x => x * 100 : undefined} = options[scale] || {};
if (transform != null) channel.value = Array.from(channel.value, transform);
if (transform != null) channel.value = map(channel.value, transform);
}
}
return channels;
Expand Down
6 changes: 3 additions & 3 deletions src/scales.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {parse as isoParse} from "isoformat";
import {isColor, isEvery, isOrdinal, isFirst, isTemporal, isTemporalString, isNumericString, isScaleOptions, isTypedArray, map, order} from "./options.js";
import {isColor, isEvery, isOrdinal, isFirst, isTemporal, isTemporalString, isNumericString, isScaleOptions, isTypedArray, map, order, slice} from "./options.js";
import {registry, color, position, radius, opacity, symbol, length} from "./scales/index.js";
import {ScaleLinear, ScaleSqrt, ScalePow, ScaleLog, ScaleSymlog, ScaleQuantile, ScaleQuantize, ScaleThreshold, ScaleIdentity} from "./scales/quantitative.js";
import {ScaleDiverging, ScaleDivergingSqrt, ScaleDivergingPow, ScaleDivergingLog, ScaleDivergingSymlog} from "./scales/diverging.js";
Expand Down Expand Up @@ -415,8 +415,8 @@ function exposeScale({
const unknown = scale.unknown ? scale.unknown() : undefined;
return {
type,
domain: Array.from(domain), // defensive copy
...range !== undefined && {range: Array.from(range)}, // defensive copy
domain: slice(domain), // defensive copy
...range !== undefined && {range: slice(range)}, // defensive copy
...transform !== undefined && {transform},
...percent && {percent}, // only exposed if truthy
...label !== undefined && {label},
Expand Down
4 changes: 2 additions & 2 deletions src/scales/ordinal.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {InternSet, quantize, reverse as reverseof, sort, symbolsFill, symbolsStroke} from "d3";
import {scaleBand, scaleOrdinal, scalePoint, scaleImplicit} from "d3";
import {ascendingDefined} from "../defined.js";
import {isNoneish} from "../options.js";
import {isNoneish, map} from "../options.js";
import {maybeSymbol} from "../symbols.js";
import {registry, color, symbol} from "./index.js";
import {maybeBooleanRange, ordinalScheme, quantitativeScheme} from "./schemes.js";
Expand Down Expand Up @@ -41,7 +41,7 @@ export function ScaleOrdinal(key, channels, {
let hint;
if (registry.get(key) === symbol) {
hint = inferSymbolHint(channels);
range = range === undefined ? inferSymbolRange(hint) : Array.from(range, maybeSymbol);
range = range === undefined ? inferSymbolRange(hint) : map(range, maybeSymbol);
} else if (registry.get(key) === color) {
if (range === undefined && (type === "ordinal" || type === ordinalImplicit)) {
range = maybeBooleanRange(domain, scheme);
Expand Down
4 changes: 2 additions & 2 deletions src/scales/quantitative.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
ticks
} from "d3";
import {positive, negative, finite} from "../defined.js";
import {arrayify, constant, order} from "../options.js";
import {arrayify, constant, order, slice} from "../options.js";
import {ordinalRange, quantitativeScheme} from "./schemes.js";
import {registry, radius, opacity, color, length} from "./index.js";

Expand Down Expand Up @@ -94,7 +94,7 @@ export function ScaleQ(key, scale, channels, {
if (zero) {
const [min, max] = extent(domain);
if ((min > 0) || (max < 0)) {
domain = Array.from(domain);
domain = slice(domain);
if (order(domain) < 0) domain[domain.length - 1] = 0;
else domain[0] = 0;
}
Expand Down
6 changes: 3 additions & 3 deletions src/transforms/interval.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {range} from "d3";
import {isTemporal, labelof, maybeValue, valueof} from "../options.js";
import {isTemporal, labelof, map, maybeValue, valueof} from "../options.js";
import {maybeInsetX, maybeInsetY} from "./inset.js";

// TODO Allow the interval to be specified as a string, e.g. “day” or “hour”?
Expand Down Expand Up @@ -46,7 +46,7 @@ function maybeIntervalK(k, maybeInsetK, options, trivial) {
let D1, V1;
function transform(data) {
if (V1 !== undefined && data === D1) return V1; // memoize
return V1 = Array.from(valueof(D1 = data, value), v => interval.floor(v));
return V1 = map(valueof(D1 = data, value), v => interval.floor(v));
}
return maybeInsetK({
...options,
Expand All @@ -65,7 +65,7 @@ function maybeIntervalMidK(k, maybeInsetK, options) {
[k]: {
label: labelof(v),
transform: data => {
const V1 = Array.from(valueof(data, value), v => interval.floor(v));
const V1 = map(valueof(data, value), v => interval.floor(v));
const V2 = V1.map(v => interval.offset(v));
return V1.map(isTemporal(V1)
? (v1, v2) => v1 == null || isNaN(v1 = +v1) || (v2 = V2[v2], v2 == null) || isNaN(v2 = +v2) ? undefined : new Date((v1 + v2) / 2)
Expand Down