Updated d3-array and related tests.

Definitions and tests up-to-date with release 1.12.0 including complete d3-array and d3-quadtree.
This commit is contained in:
Tom Wanzek
2016-07-18 20:05:59 -04:00
parent 020b196481
commit 2789798ab3
2 changed files with 194 additions and 41 deletions

View File

@@ -7,6 +7,8 @@
*/
import * as d3 from 'd3-array';
import { scaleTime } from 'd3-scale';
import { timeYear } from 'd3-time';
// -----------------------------------------------------------------------------
// Preparatory Steps
@@ -252,7 +254,7 @@ num = d3.variance(mixedObjectArray, function (datum, index, array) {
});
// -----------------------------------------------------------------------------
// Test Searching Arrrays
// Test Searching Arrays
// -----------------------------------------------------------------------------
// scan() ----------------------------------------------------------------------
@@ -263,19 +265,72 @@ num = d3.scan(mixedObjectArray, function (a, b) {
// bisectLeft() ----------------------------------------------------------------
// TODO: complete
num = d3.bisectLeft([0, 2, 3, 4, 7, 8], 4);
num = d3.bisectLeft([0, 2, 3, 4, 7, 8], 4, 1);
num = d3.bisectLeft([0, 2, 3, 4, 7, 8], 4, 1, 4);
// bisect() --------------------------------------------------------------------
num = d3.bisectLeft(['0', '2', '3', '4', '7', '8'], '21');
num = d3.bisectLeft(['0', '2', '3', '4', '7', '8'], '21', 1);
num = d3.bisectLeft(['0', '2', '3', '4', '7', '8'], '21', 1, 4);
// TODO: complete
num = d3.bisectLeft([new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)], new Date(2011, 2, 1));
num = d3.bisectLeft([new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)], new Date(2011, 2, 1), 1);
num = d3.bisectLeft([new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)], new Date(2011, 2, 1), 1, 2);
// bisectRight() ---------------------------------------------------------------
// TODO: complete
num = d3.bisectRight([0, 2, 3, 4, 7, 8], 4);
num = d3.bisectRight([0, 2, 3, 4, 7, 8], 4, 1);
num = d3.bisectRight([0, 2, 3, 4, 7, 8], 4, 1, 4);
num = d3.bisectRight(['0', '2', '3', '4', '7', '8'], '21');
num = d3.bisectRight(['0', '2', '3', '4', '7', '8'], '21', 1);
num = d3.bisectRight(['0', '2', '3', '4', '7', '8'], '21', 1, 4);
num = d3.bisectRight([new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)], new Date(2011, 2, 1));
num = d3.bisectRight([new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)], new Date(2011, 2, 1), 1);
num = d3.bisectRight([new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)], new Date(2011, 2, 1), 1, 2);
// bisect() --------------------------------------------------------------------
num = d3.bisect([0, 2, 3, 4, 7, 8], 4);
num = d3.bisect([0, 2, 3, 4, 7, 8], 4, 1);
num = d3.bisect([0, 2, 3, 4, 7, 8], 4, 1, 4);
num = d3.bisect(['0', '2', '3', '4', '7', '8'], '21');
num = d3.bisect(['0', '2', '3', '4', '7', '8'], '21', 1);
num = d3.bisect(['0', '2', '3', '4', '7', '8'], '21', 1, 4);
num = d3.bisect([new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)], new Date(2011, 2, 1));
num = d3.bisect([new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)], new Date(2011, 2, 1), 1);
num = d3.bisect([new Date(2010, 1, 1), new Date(2011, 1, 1), new Date(2012, 1, 1), new Date(2013, 1, 1)], new Date(2011, 2, 1), 1, 2);
// bisector() ------------------------------------------------------------------
// TODO: complete
mixedObjectArray.sort(function (a, b) { return a.date.valueOf() - b.date.valueOf(); });
let mixedObjectDateBisectorObject: d3.Bisector<MixedObject, Date>;
// define using accessor
mixedObjectDateBisectorObject = d3.bisector<MixedObject, Date>(function (el) {
return el.date;
});
// define using comparator
mixedObjectDateBisectorObject = d3.bisector<MixedObject, Date>(function (el, x) {
return el.date.valueOf() - x.valueOf();
});
// bisect left
num = mixedObjectDateBisectorObject.left(mixedObjectArray, new Date(2015, 3, 14));
num = mixedObjectDateBisectorObject.left(mixedObjectArray, new Date(2015, 3, 14), 1);
num = mixedObjectDateBisectorObject.left(mixedObjectArray, new Date(2015, 3, 14), 3, 4);
// bisect right
num = mixedObjectDateBisectorObject.right(mixedObjectArray, new Date(2015, 3, 14));
num = mixedObjectDateBisectorObject.right(mixedObjectArray, new Date(2015, 3, 14), 1);
num = mixedObjectDateBisectorObject.right(mixedObjectArray, new Date(2015, 3, 14), 3, 4);
// ascending() -----------------------------------------------------------------
@@ -395,35 +450,102 @@ testArrays = d3.zip(
// Test Histogram
// -----------------------------------------------------------------------------
let tScale = scaleTime();
// Create histogram generator ==================================================
let defaultHistogram: d3.HistogramGenerator<number>;
let defaultHistogram: d3.HistogramGenerator<number, number>;
defaultHistogram = d3.histogram();
let testHistogram: d3.HistogramGenerator<MixedObject>;
testHistogram = d3.histogram<MixedObject>();
let testHistogram: d3.HistogramGenerator<MixedObject, Date>;
testHistogram = d3.histogram<MixedObject, Date>();
// Configure histogram generator ===============================================
// value(...) ------------------------------------------------------------------
testHistogram = testHistogram.value(function (d, i, data) {
let datum: MixedObject = d; // d is of type MixedObject
let index: number = i; // i is number
let array: MixedObject[] = data; // data is of type MixedObject[]
return datum.date;
});
let valueAccessorFn: (d: MixedObject, i: number, data: MixedObject[]) => Date;
valueAccessorFn = testHistogram.value();
// domain(...) -----------------------------------------------------------------
// test with array
testHistogram = testHistogram.domain([new Date(2014, 3, 15), new Date(2017, 4, 15)]);
// usage with scale domain:
let domain = tScale.domain();
testHistogram = testHistogram.domain([domain[0], domain[domain.length]]);
// testHistogram = testHistogram.domain(tScale.domain()); // fails, as scale domain is an array with possibly more than the two elements expected by histogram
// use with accessor function
testHistogram = testHistogram.domain(function (values) {
return [values[0], values[values.length]];
});
// get current domain accessor function
let domainAccessorFn: (values: Date[]) => [Date, Date];
domainAccessorFn = testHistogram.domain();
// thresholds(...) -------------------------------------------------------------
// with count constant
defaultHistogram = defaultHistogram.thresholds(3);
// with threshold count generator
defaultHistogram = defaultHistogram.thresholds(d3.thresholdScott);
// with thresholds value array
testHistogram = testHistogram.thresholds([new Date(2015, 11, 15), new Date(2016, 6, 1), new Date(2016, 8, 30)]);
// with thresholds value array accessors
testHistogram = testHistogram.thresholds(function (values: Date[], min: Date, max: Date) {
let thresholds: Date[];
thresholds = [values[0], values[2], values[4]];
return thresholds;
});
testHistogram = testHistogram.thresholds(tScale.ticks(timeYear));
// Use histogram generator =====================================================
let bins: Array<d3.Bin<MixedObject>>;
bins = testHistogram(mixedObjectArray);
let defaultBins: Array<d3.Bin<number, number>>;
defaultBins = defaultHistogram([-1, 0, 1, 1, 3, 20, 234]);
let defaultBin: d3.Bin<number, number>;
defaultBin = defaultBins[0];
num = defaultBin.length; // defaultBin is array
num = defaultBin[0]; // with element type number
num = defaultBin.x0; // bin lower bound is number
num = defaultBin.x1; // bin upper bound is number
let testBins: Array<d3.Bin<MixedObject, Date>>;
testBins = testHistogram(mixedObjectArray);
let testBin: d3.Bin<MixedObject, Date>;
testBin = testBins[0];
num = testBin.length; // defaultBin is array
let mixedObject: MixedObject = testBin[0]; // with element type MixedObject
date = testBin.x0; // bin lower bound is Date
date = testBin.x1; // bin upper bound is Date
// Note currently bins returned are as follows: !!!
// first bin.x0:T bin.x1:number,
// interior bin.x0:number, bin.x1:number
// last bin.x0:number, bin.x1:T
// Histogram Tresholds =========================================================
// TODO: Complete
num = d3.thresholdFreedmanDiaconis([-1, 0, 1, 1, 3, 20, 234], -1, 234);
num = d3.thresholdScott([-1, 0, 1, 1, 3, 20, 234], -1, 234);
num = d3.thresholdSturges([-1, 0, 1, 1, 3, 20, 234]);

81
d3-array/index.d.ts vendored
View File

@@ -175,27 +175,29 @@ export function variance<T>(array: T[], accessor: (datum: T, index: number, arra
// --------------------------------------------------------------------------------------
// Searching Arrrays
// Searching Arrays
// --------------------------------------------------------------------------------------
export function scan<T>(array: T[], comparator: (a: T, b: T) => number): number;
export function bisectLeft(array: number[], x: number, lo?: number, hi?: number): number;
export function bisectLeft(array: string[], x: string, lo?: number, hi?: number): number;
export function bisectLeft(array: Date[], x: Date, lo?: number, hi?: number): number;
export function bisectRight(array: number[], x: number, lo?: number, hi?: number): number;
export function bisectRight(array: string[], x: string, lo?: number, hi?: number): number;
export function bisectRight(array: Date[], x: Date, lo?: number, hi?: number): number;
export var bisect: typeof bisectRight;
export function bisectRight<T>(array: T[], x: T, lo?: number, hi?: number): number;
export function bisector<T, U>(accessor: (x: T) => U): {
export interface Bisector<T, U> {
left: (array: T[], x: U, lo?: number, hi?: number) => number;
right: (array: T[], x: U, lo?: number, hi?: number) => number;
}
export function bisector<T, U>(comparator: (a: T, b: U) => number): {
left: (array: T[], x: U, lo?: number, hi?: number) => number;
right: (array: T[], x: U, lo?: number, hi?: number) => number;
}
export function bisector<T, U>(accessor: (x: T) => U): Bisector<T, U>;
export function bisector<T, U>(comparator: (a: T, b: U) => number): Bisector<T, U>
// NB. this is limited to primitive values due to D3's use of the <, >, and >= operators. Results get weird for object instances.
/**
@@ -281,9 +283,9 @@ export function zip<T>(...arrays: T[][]): T[][];
// Histogram
// --------------------------------------------------------------------------------------
export interface Bin<T> extends Array<T> {
x0: number;
x1: number;
export interface Bin<Datum, Value extends number | Date> extends Array<Datum> {
x0: Value;
x1: Value;
}
/**
@@ -294,25 +296,54 @@ export type ThresholdCountGenerator = (values: number[], min?: number, max?: num
/**
* Type definition for threshold generator which returns an array of recommended thresholds
*/
export type ThresholdArrayGenerator = (values: number[], min?: number, max?: number) => number[];
export type ThresholdArrayGenerator<Value extends number | Date> = (values: Value[], min?: Value, max?: Value) => Value[];
export interface HistogramGenerator<T> {
(data: T[]): Array<Bin<T>>;
value(): (d: T, i: number, data: T[]) => number;
value(valueAccessor: (d: T, i: number, data: T[]) => number): HistogramGenerator<T>;
domain(): (values: number[]) => [number, number];
domain(domainAccessor: (values: number[]) => [number, number]): HistogramGenerator<T>;
thresholds(): ThresholdCountGenerator | ThresholdArrayGenerator;
thresholds(count: number): HistogramGenerator<T>;
thresholds(thresholds: number[]): HistogramGenerator<T>;
thresholds(thresholds: ThresholdCountGenerator): HistogramGenerator<T>;
thresholds(thresholds: ThresholdArrayGenerator): HistogramGenerator<T>;
export interface HistogramGenerator<Datum, Value extends number | Date> {
(data: Datum[]): Array<Bin<Datum, Value>>;
value(): (d: Datum, i: number, data: Datum[]) => Value;
value(valueAccessor: (d: Datum, i: number, data: Datum[]) => Value): this;
domain(): (values: Value[]) => [Value, Value];
domain(domain: [Value, Value]): this;
domain(domainAccessor: (values: Value[]) => [Value, Value]): this;
thresholds(): ThresholdCountGenerator | ThresholdArrayGenerator<Value>;
/**
* Divide the domain uniformly into approximately count bins. IMPORTANT: This threshold
* setting approach only works, when the materialized values are numbers!
*
* @param count The desired number of uniform bins.
*/
thresholds(count: number): this;
/**
* Set a threshold accessor function, which returns the desired number of bins.
* Divides the domain uniformly into approximately count bins. IMPORTANT: This threshold
* setting approach only works, when the materialized values are numbers!
*
* @param count A function which accepts as arguments the array of materialized values, and
* optionally the domain minimum and maximum. The function calcutates and returns the suggested
* number of bins.
*/
thresholds(count: ThresholdCountGenerator): this;
/**
* Set the array of values to be used as thresholds in determining the bins.
* @param thresholds Array of threshold values used for binning. The elements must
* be of the same type as the materialized values of the histogram.
*/
thresholds(thresholds: Value[]): this;
/**
* Set a threshold accessor function, which returns the array of values to be used as
* thresholds in determining the bins.
*
* @param thresholds A function which accepts as arguments the array of materialized values, and
* optionally the domain minimum and maximum. The function calcutates and returns the array of values to be used as
* thresholds in determining the bins.
*/
thresholds(thresholds: ThresholdArrayGenerator<Value>): this;
}
export function histogram(): HistogramGenerator<number>;
export function histogram<T>(): HistogramGenerator<T>;
export function histogram(): HistogramGenerator<number, number>;
export function histogram<Datum, Value extends number | Date>(): HistogramGenerator<Datum, Value>;
// --------------------------------------------------------------------------------------
// Histogram Thresholds