jupyter-ijavascript-utils 1.9.2 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS.md +2 -0
- package/README.md +3 -1
- package/package.json +2 -2
- package/src/TableGenerator.js +135 -10
- package/src/aggregate.js +283 -0
- package/src/format.js +1 -0
- package/src/object.js +35 -0
package/DOCS.md
CHANGED
|
@@ -28,6 +28,8 @@ See the [#Installation section for requirements and installation](#install)
|
|
|
28
28
|
|
|
29
29
|
## What's New
|
|
30
30
|
|
|
31
|
+
* 1.11 - provide {@link module:aggregate.topValues|topValues} (like top 5, bottom 3)
|
|
32
|
+
* 1.10 - provide {@link module:aggregate.percentile|percentile} (like 50th percentile) aggregates
|
|
31
33
|
* 1.9 - allow {@link TableGenerator#transpose|transposing results} on TableGenerator.
|
|
32
34
|
* 1.8 - add in What can I Do tutorial, and {@link module:object.join|object.join methods}
|
|
33
35
|
* 1.7 - revamp of `animation` method for ijs.htmlScript
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</a>
|
|
8
8
|
<img src="https://img.shields.io/badge/Coverage-98-green" />
|
|
9
9
|
<a href="https://github.com/paulroth3d/jupyter-ijavascript-utils" alt="npm">
|
|
10
|
-
<img src="https://img.shields.io/badge/npm-%5E1.
|
|
10
|
+
<img src="https://img.shields.io/badge/npm-%5E1.11.0-red" />
|
|
11
11
|
</a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
@@ -21,6 +21,8 @@ See documentation at: [https://jupyter-ijavascript-utils.onrender.com/](https://
|
|
|
21
21
|
|
|
22
22
|
# What's New
|
|
23
23
|
|
|
24
|
+
* 1.11 - provide topValues (like top 5, bottom 3)
|
|
25
|
+
* 1.10 - provide percentile (like 50th percentile) aggregates
|
|
24
26
|
* 1.9 - allow transposing results on TableGenerator.
|
|
25
27
|
* 1.8 - add in What can I Do tutorial, and object.join methods
|
|
26
28
|
* 1.7 - revamp of `animation` method to htmlScript
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyter-ijavascript-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Utilities for working with iJavaScript - a Jupyter Kernel",
|
|
5
5
|
"homepage": "https://jupyter-ijavascript-utils.onrender.com/",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"jupyter"
|
|
28
28
|
],
|
|
29
29
|
"author": "Paul Roth",
|
|
30
|
-
"license": "MIT",
|
|
31
30
|
"devDependencies": {
|
|
32
31
|
"babel-eslint": "^10.1.0",
|
|
33
32
|
"docdash": "^1.2.0",
|
|
@@ -44,6 +43,7 @@
|
|
|
44
43
|
"fs-extra": "^10.0.1",
|
|
45
44
|
"generate-schema": "^2.6.0",
|
|
46
45
|
"node-fetch": "^2.6.5",
|
|
46
|
+
"percentile": "^1.6.0",
|
|
47
47
|
"pino": "^6.12.0",
|
|
48
48
|
"pino-pretty": "^5.1.2",
|
|
49
49
|
"plantuml-encoder": "^1.4.0",
|
package/src/TableGenerator.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const { printValue } = require('./format');
|
|
15
15
|
|
|
16
|
-
const generateRange = (length, defaultValue) => new Array(length).fill(defaultValue);
|
|
16
|
+
// const generateRange = (length, defaultValue) => new Array(length).fill(defaultValue);
|
|
17
17
|
|
|
18
18
|
const IJSUtils = require('./ijs');
|
|
19
19
|
|
|
@@ -82,6 +82,7 @@ const { createSort } = require('./array');
|
|
|
82
82
|
* * {@link TableGenerator#styleHeader|styleHeader(string)} - css styles for the header row
|
|
83
83
|
* * {@link TableGenerator#styleRow|styleRow(fn)} - Function to style rows
|
|
84
84
|
* * {@link TableGenerator#styleCell|styleCell(fn)} - Function to style cells
|
|
85
|
+
* * {@link TableGenerator#border|border(string)} - Apply a border to the table data cells
|
|
85
86
|
* * generate output
|
|
86
87
|
* * {@link TableGenerator#generateHTML|generateHTML()} - returns html table with the results
|
|
87
88
|
* * {@link TableGenerator#generateMarkdown|generateMarkdown()} - returns markdown with the results
|
|
@@ -105,6 +106,12 @@ class TableGenerator {
|
|
|
105
106
|
*/
|
|
106
107
|
#augmentFn = null;
|
|
107
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Border CSS to also apply to the cells
|
|
111
|
+
* @type {String}
|
|
112
|
+
*/
|
|
113
|
+
#borderCSS = ''; // 'solid 1px #AAA';
|
|
114
|
+
|
|
108
115
|
/**
|
|
109
116
|
* Optional array of exclusive columns to show based on the properties of each row\n
|
|
110
117
|
* ex: ['Miles_per_Gallon', 'Name', 'Cylinders', etc]
|
|
@@ -235,6 +242,7 @@ class TableGenerator {
|
|
|
235
242
|
reset() {
|
|
236
243
|
this.#data = [];
|
|
237
244
|
this.#augmentFn = null;
|
|
245
|
+
this.#borderCSS = '';
|
|
238
246
|
this.#columns = null;
|
|
239
247
|
this.#columnsToExclude = [];
|
|
240
248
|
this.#fetch = null;
|
|
@@ -338,6 +346,62 @@ class TableGenerator {
|
|
|
338
346
|
return this;
|
|
339
347
|
}
|
|
340
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Convenience function to set an a border on the Data Cells.
|
|
351
|
+
*
|
|
352
|
+
* This only applies when {@link TableGenerator#render|rendering HTML}
|
|
353
|
+
* or {@link TableGenerator#generateHTML|generating HTML}
|
|
354
|
+
*
|
|
355
|
+
* As this adds additional CSS, the styling applied:
|
|
356
|
+
* * {@link TableGenerator#styleTable|to the whole table}
|
|
357
|
+
* * or {@link TableGenerator#styleRow|to the rows}
|
|
358
|
+
* * or {@link TableGenerator#styleCell|to the data cells} will be affected
|
|
359
|
+
*
|
|
360
|
+
* For example:
|
|
361
|
+
*
|
|
362
|
+
* ```
|
|
363
|
+
* sourceData = [{id: 1, temp_F:98}, {id: 2, temp_F:99}, {id: 3, temp_F:100}];
|
|
364
|
+
*
|
|
365
|
+
* new utils.TableGenerator(sourceData)
|
|
366
|
+
* .border('1px solid #aaa')
|
|
367
|
+
* .render();
|
|
368
|
+
* ```
|
|
369
|
+
*
|
|
370
|
+
* <table cellspacing="0px" >
|
|
371
|
+
* <tr >
|
|
372
|
+
* <th>id</th>
|
|
373
|
+
* <th>temp_F</th>
|
|
374
|
+
* </tr>
|
|
375
|
+
* <tr >
|
|
376
|
+
* <td style=" border: 1px solid #aaa">1</td>
|
|
377
|
+
* <td style=" border: 1px solid #aaa">98</td>
|
|
378
|
+
* </tr>
|
|
379
|
+
* <tr >
|
|
380
|
+
* <td style=" border: 1px solid #aaa">2</td>
|
|
381
|
+
* <td style=" border: 1px solid #aaa">99</td>
|
|
382
|
+
* </tr>
|
|
383
|
+
* <tr >
|
|
384
|
+
* <td style=" border: 1px solid #aaa">3</td>
|
|
385
|
+
* <td style=" border: 1px solid #aaa">100</td>
|
|
386
|
+
* </tr>
|
|
387
|
+
* </table>
|
|
388
|
+
*
|
|
389
|
+
* @param {String | Boolean} borderCSS - CSS String to additionally apply HTML TD elements
|
|
390
|
+
*/
|
|
391
|
+
border(borderCSS) {
|
|
392
|
+
let cleanCSS = '';
|
|
393
|
+
|
|
394
|
+
if (borderCSS === true) {
|
|
395
|
+
cleanCSS = 'border: 1px solid #AAA';
|
|
396
|
+
} else if (borderCSS) {
|
|
397
|
+
cleanCSS = `border: ${borderCSS}`;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
this.#borderCSS = cleanCSS;
|
|
401
|
+
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
|
|
341
405
|
/**
|
|
342
406
|
* Applies an optional set of columns / properties to render
|
|
343
407
|
*
|
|
@@ -452,20 +516,64 @@ class TableGenerator {
|
|
|
452
516
|
*
|
|
453
517
|
* (This is an alternate to {@link formatterFn} or simple `.map()` call on the source data)
|
|
454
518
|
*
|
|
519
|
+
* **NOTE: Only matching properties on the formatter object are changed - all others are left alone.**
|
|
520
|
+
*
|
|
455
521
|
* For example:
|
|
456
522
|
*
|
|
457
523
|
* ```
|
|
458
|
-
* data = [
|
|
524
|
+
* data = [
|
|
525
|
+
* {station: 'A', temp: 98, type: 'F', descr: '0123'},
|
|
526
|
+
* {station: 'A', temp: 99, type: 'F', descr: '0123456'},
|
|
527
|
+
* {station: 'A', temp: 100, type: 'F', descr: '0123456789'}
|
|
528
|
+
* ];
|
|
459
529
|
*
|
|
460
530
|
* //-- simple example where the temp property is converted, and type property overwritten
|
|
461
531
|
* new TableGenerator(data)
|
|
462
532
|
* .formatter({
|
|
533
|
+
* //-- property 'station' not mentioned, so no change
|
|
534
|
+
*
|
|
535
|
+
* //-- convert temperature to celsius
|
|
463
536
|
* temp: (value) => (value - 32) * 0.5556,
|
|
464
|
-
* type
|
|
465
|
-
*
|
|
537
|
+
* //-- overwrite type from 'F' to 'C'
|
|
538
|
+
* type: 'C',
|
|
539
|
+
* //-- ellipsify to shorten the description string, if longer than 8 characters
|
|
540
|
+
* descr: (str) => utils.format.ellipsify(str, 8)
|
|
541
|
+
* }).renderMarkdown()
|
|
466
542
|
* ```
|
|
467
543
|
*
|
|
468
|
-
*
|
|
544
|
+
* station|temp |type|descr
|
|
545
|
+
* -- |-- |-- |--
|
|
546
|
+
* A |36.67 |F |0123
|
|
547
|
+
* A |37.225|F |0123456
|
|
548
|
+
* A |37.781|F |01234567…
|
|
549
|
+
*
|
|
550
|
+
* Note, due to frequent requests, simple datatype conversions can be requested.
|
|
551
|
+
*
|
|
552
|
+
* Only ('String', 'Number', and 'Boolean') are supported
|
|
553
|
+
*
|
|
554
|
+
* ```
|
|
555
|
+
* data = [
|
|
556
|
+
* { propA: ' 8009', propB: 8009, isBoolean: 0},
|
|
557
|
+
* { propA: ' 92032', propB: 92032, isBoolean: 1},
|
|
558
|
+
* { propA: ' 234234', propB: 234234, isBoolean: 1},
|
|
559
|
+
* ];
|
|
560
|
+
*
|
|
561
|
+
* new utils.TableGenerator(data)
|
|
562
|
+
* .formatter({
|
|
563
|
+
* //-- convert Prop A to Number - so render with Locale Number Formatting
|
|
564
|
+
* propA: 'number',
|
|
565
|
+
* //-- conver PropB to String - so render without Locale Number Formatting
|
|
566
|
+
* propB: 'string',
|
|
567
|
+
* //-- render 'True' or 'False'
|
|
568
|
+
* isBoolean: 'boolean'
|
|
569
|
+
* }).renderMarkdown();
|
|
570
|
+
* ```
|
|
571
|
+
*
|
|
572
|
+
* propA|propB|isBoolean
|
|
573
|
+
* -- |-- |--
|
|
574
|
+
* 8,009 |8009 |false
|
|
575
|
+
* 92,032 |92032 |true
|
|
576
|
+
* 234,234 |234234 |true
|
|
469
577
|
*
|
|
470
578
|
* @param {Object} obj - object with properties storing arrow functions
|
|
471
579
|
* @param {Function} obj.PropertyToTranslate - (value) => result
|
|
@@ -480,10 +588,25 @@ class TableGenerator {
|
|
|
480
588
|
|
|
481
589
|
const fnMap = new Map();
|
|
482
590
|
Object.getOwnPropertyNames(obj).forEach((key) => {
|
|
483
|
-
if ((typeof obj[key])
|
|
484
|
-
|
|
591
|
+
if ((typeof obj[key]) === 'string') {
|
|
592
|
+
let fn;
|
|
593
|
+
const str = obj[key].toLowerCase();
|
|
594
|
+
if (str === 'string') {
|
|
595
|
+
fn = (val) => String(val);
|
|
596
|
+
} else if (str === 'number') {
|
|
597
|
+
fn = (val) => Number(val);
|
|
598
|
+
} else if (str === 'boolean') {
|
|
599
|
+
fn = (val) => val ? 'true' : 'false';
|
|
600
|
+
} else {
|
|
601
|
+
throw Error(`TableGenerator.format: property ${key} formatter of ${str} is unsupported. Only (String, Number, Boolean) are supported`);
|
|
602
|
+
}
|
|
603
|
+
fnMap.set(key, fn);
|
|
604
|
+
} else {
|
|
605
|
+
if ((typeof obj[key]) !== 'function') {
|
|
606
|
+
throw (Error(`Formatter properties must be functions. [${key}]`));
|
|
607
|
+
}
|
|
608
|
+
fnMap.set(key, obj[key]);
|
|
485
609
|
}
|
|
486
|
-
fnMap.set(key, obj[key]);
|
|
487
610
|
});
|
|
488
611
|
|
|
489
612
|
this.#formatterFn = ({ value, property }) => fnMap.has(property)
|
|
@@ -928,6 +1051,7 @@ class TableGenerator {
|
|
|
928
1051
|
const styleRowFn = this.#styleRow;
|
|
929
1052
|
const styleCellFn = this.#styleCell;
|
|
930
1053
|
const printOptions = this.#printOptions;
|
|
1054
|
+
const borderCSS = this.#borderCSS;
|
|
931
1055
|
|
|
932
1056
|
const cleanFn = printValue;
|
|
933
1057
|
|
|
@@ -948,16 +1072,17 @@ class TableGenerator {
|
|
|
948
1072
|
+ dataRow.map((value, columnIndex) => {
|
|
949
1073
|
//-- note - the data is from the original dataset, not the results
|
|
950
1074
|
const cellStyle = !styleCellFn
|
|
951
|
-
?
|
|
1075
|
+
? ''
|
|
952
1076
|
: styleCellFn({ value, columnIndex, rowIndex, row: dataRow, record });
|
|
953
1077
|
return '<td '
|
|
954
|
-
+ (
|
|
1078
|
+
+ (borderCSS || cellStyle ? `style="${cellStyle} ${borderCSS}"` : '')
|
|
955
1079
|
+ `>${cleanFn(value, printOptions)}</td>`;
|
|
956
1080
|
}).join('\n\t')
|
|
957
1081
|
+ '\n</tr>';
|
|
958
1082
|
}).join('\n');
|
|
959
1083
|
|
|
960
1084
|
const tableResults = '<table '
|
|
1085
|
+
+ 'cellspacing="0px" '
|
|
961
1086
|
+ (!styleTable ? '' : `style="${styleTable}"`)
|
|
962
1087
|
+ '>'
|
|
963
1088
|
+ printHeader(results.headers, '')
|
package/src/aggregate.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/* eslint-disable implicit-arrow-linebreak */
|
|
2
2
|
|
|
3
|
+
const Percentile = require('percentile');
|
|
4
|
+
|
|
5
|
+
const ArrayUtils = require('./array');
|
|
3
6
|
const ObjectUtils = require('./object');
|
|
4
7
|
const FormatUtils = require('./format');
|
|
5
8
|
|
|
@@ -13,6 +16,8 @@ const FormatUtils = require('./format');
|
|
|
13
16
|
*
|
|
14
17
|
* Types of methods:
|
|
15
18
|
*
|
|
19
|
+
* * Select a single property
|
|
20
|
+
* * {@link module:aggregate.property|property()} - maps to a single property (often used with other libraries)
|
|
16
21
|
* * Ranges of values
|
|
17
22
|
* * {@link module:aggregate.extent|extent()} - returns the min and max of range
|
|
18
23
|
* * {@link module:aggregate.min|min()} - returns the minimum value of the range
|
|
@@ -35,6 +40,19 @@ const FormatUtils = require('./format');
|
|
|
35
40
|
* * {@link module:aggregate.sum|sum()} - sum of a collection
|
|
36
41
|
* * Functional
|
|
37
42
|
* * {@link module:aggregate.deferCollection|deferCollection(function, bindArg, bindArg, ...)} - bind a function with arguments
|
|
43
|
+
* * Percentile
|
|
44
|
+
* * {@link module:aggregate.percentile|percentile()} - determines the Nth percentile of a field or value
|
|
45
|
+
* * {@link module:aggregate.percentile_01|percentile_01()} - 1th percentile
|
|
46
|
+
* * {@link module:aggregate.percentile_05|percentile_05()} - 5th percentile
|
|
47
|
+
* * {@link module:aggregate.percentile_10|percentile_10()} - 10th percentile
|
|
48
|
+
* * {@link module:aggregate.percentile_25|percentile_25()} - 25th percentile
|
|
49
|
+
* * {@link module:aggregate.percentile_50|percentile_50()} - 50th percentile
|
|
50
|
+
* * {@link module:aggregate.percentile_75|percentile_75()} - 75th percentile
|
|
51
|
+
* * {@link module:aggregate.percentile_90|percentile_90()} - 90th percentile
|
|
52
|
+
* * {@link module:aggregate.percentile_95|percentile_95()} - 95th percentile
|
|
53
|
+
* * {@link module:aggregate.percentile_99|percentile_99()} - 99th percentile
|
|
54
|
+
* * Top Values
|
|
55
|
+
* * {@link module:aggregate.topValues|topValues} - top (or bottom) values from a list of objects or literals
|
|
38
56
|
*
|
|
39
57
|
* Please note, there is nothing special for these functions, such as working with {@link SourceMap#reduce|SourceMap.reduce()}
|
|
40
58
|
*
|
|
@@ -225,6 +243,34 @@ module.exports = {};
|
|
|
225
243
|
// eslint-disable-next-line no-unused-vars
|
|
226
244
|
const AggregateUtils = module.exports;
|
|
227
245
|
|
|
246
|
+
/**
|
|
247
|
+
* Maps an array of values to a single property.
|
|
248
|
+
*
|
|
249
|
+
* For example:
|
|
250
|
+
*
|
|
251
|
+
* ```
|
|
252
|
+
* const data = [{ record: 'jobA', val: 1 }, { record: 'jobA', val: 2 },
|
|
253
|
+
* { record: 'jobA', val: 3 }, { record: 'jobA', val: 4 },
|
|
254
|
+
* { record: 'jobA', val: 5 }, { record: 'jobA', val: 6 },
|
|
255
|
+
* { record: 'jobA', val: 7 }, { record: 'jobA', val: 8 },
|
|
256
|
+
* { record: 'jobA', val: 9 }, { record: 'jobA', val: 10 }
|
|
257
|
+
* ];
|
|
258
|
+
*
|
|
259
|
+
* utils.object.propertyFromList(data, 'val')
|
|
260
|
+
* //-- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
261
|
+
*
|
|
262
|
+
* utils.object.propertyFromList(data, (r) => r.val);
|
|
263
|
+
* //-- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
264
|
+
* ```
|
|
265
|
+
*
|
|
266
|
+
* @param {Object[]} objectArray - Array of Objects to be mapped to a single property / value
|
|
267
|
+
* @param {Function | String} propertyOrFn - Name of the property or Function to return a value
|
|
268
|
+
* @returns {Array} - Array of values
|
|
269
|
+
*/
|
|
270
|
+
module.exports.property = function propertyFromList(objectArray, propertyOrFn) {
|
|
271
|
+
return ObjectUtils.propertyFromList(objectArray, propertyOrFn);
|
|
272
|
+
};
|
|
273
|
+
|
|
228
274
|
/**
|
|
229
275
|
* Converts an aggregate function to two functions -
|
|
230
276
|
* one that takes all arguments except the collection
|
|
@@ -662,3 +708,240 @@ module.exports.isUnique = function isUnique(collection, accessor) {
|
|
|
662
708
|
});
|
|
663
709
|
return duplicateValue === undefined;
|
|
664
710
|
};
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Returns a given percentile from a list of objects.
|
|
714
|
+
*
|
|
715
|
+
* **Note: this simply aggregates the values and passes to the [Percentile NPM Package](https://www.npmjs.com/package/percentile)**
|
|
716
|
+
*
|
|
717
|
+
* @param {Object[]} collection - collection of objects
|
|
718
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
719
|
+
* @param {Number} pct - Percentile (either .5 or 50)
|
|
720
|
+
* @returns {Number} - the pct percentile of a property within the collection
|
|
721
|
+
* @example
|
|
722
|
+
* const data = [{ record: 'jobA', val: 1 }, { record: 'jobA', val: 2 },
|
|
723
|
+
* { record: 'jobA', val: 3 }, { record: 'jobA', val: 4 },
|
|
724
|
+
* { record: 'jobA', val: 5 }, { record: 'jobA', val: 6 },
|
|
725
|
+
* { record: 'jobA', val: 7 }, { record: 'jobA', val: 8 },
|
|
726
|
+
* { record: 'jobA', val: 9 }, { record: 'jobA', val: 10 }
|
|
727
|
+
* ];
|
|
728
|
+
*
|
|
729
|
+
* utils.aggregate.percentile(data, 'val', 50) //-- returns 5
|
|
730
|
+
* utils.aggregate.percentile(data, (r) => r.val, 70) //-- returns 7
|
|
731
|
+
*/
|
|
732
|
+
module.exports.percentile = function percentile(collection, accessor, pct) {
|
|
733
|
+
const values = ObjectUtils.propertyFromList(collection, accessor);
|
|
734
|
+
const cleanPercentile = pct > 0 && pct < 1
|
|
735
|
+
? pct * 100
|
|
736
|
+
: pct;
|
|
737
|
+
return Percentile(cleanPercentile, values);
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Returns a hard coded percentage
|
|
742
|
+
*
|
|
743
|
+
* {@link module:aggregate.percentage|See Percentage for more detail}
|
|
744
|
+
*
|
|
745
|
+
* @param {Object[]} collection - collection of objects
|
|
746
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
747
|
+
* @returns {Number} - the percentile of a property within the collection
|
|
748
|
+
* @see {@link module:aggregate.percentile|percentile} - as this simply hard codes the percentage
|
|
749
|
+
*/
|
|
750
|
+
module.exports.percentile_01 = function percentile(collection, accessor) {
|
|
751
|
+
return AggregateUtils.percentile(collection, accessor, 1);
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Returns a hard coded percentage
|
|
756
|
+
*
|
|
757
|
+
* {@link module:aggregate.percentage|See Percentage for more detail}
|
|
758
|
+
*
|
|
759
|
+
* @param {Object[]} collection - collection of objects
|
|
760
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
761
|
+
* @returns {Number} - the percentile of a property within the collection
|
|
762
|
+
* @see {@link module:aggregate.percentile|percentile} - as this simply hard codes the percentage
|
|
763
|
+
*/
|
|
764
|
+
module.exports.percentile_05 = function percentile(collection, accessor) {
|
|
765
|
+
return AggregateUtils.percentile(collection, accessor, 5);
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Returns a hard coded percentage
|
|
770
|
+
*
|
|
771
|
+
* {@link module:aggregate.percentage|See Percentage for more detail}
|
|
772
|
+
*
|
|
773
|
+
* @param {Object[]} collection - collection of objects
|
|
774
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
775
|
+
* @returns {Number} - the percentile of a property within the collection
|
|
776
|
+
* @see {@link module:aggregate.percentile|percentile} - as this simply hard codes the percentage
|
|
777
|
+
*/
|
|
778
|
+
module.exports.percentile_10 = function percentile(collection, accessor) {
|
|
779
|
+
return AggregateUtils.percentile(collection, accessor, 10);
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Returns a hard coded percentage
|
|
784
|
+
*
|
|
785
|
+
* {@link module:aggregate.percentage|See Percentage for more detail}
|
|
786
|
+
*
|
|
787
|
+
* @param {Object[]} collection - collection of objects
|
|
788
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
789
|
+
* @returns {Number} - the percentile of a property within the collection
|
|
790
|
+
* @see {@link module:aggregate.percentile|percentile} - as this simply hard codes the percentage
|
|
791
|
+
*/
|
|
792
|
+
module.exports.percentile_25 = function percentile(collection, accessor) {
|
|
793
|
+
return AggregateUtils.percentile(collection, accessor, 25);
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Returns a hard coded percentage
|
|
798
|
+
*
|
|
799
|
+
* {@link module:aggregate.percentage|See Percentage for more detail}
|
|
800
|
+
*
|
|
801
|
+
* @param {Object[]} collection - collection of objects
|
|
802
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
803
|
+
* @returns {Number} - the percentile of a property within the collection
|
|
804
|
+
* @see {@link module:aggregate.percentile|percentile} - as this simply hard codes the percentage
|
|
805
|
+
*/
|
|
806
|
+
module.exports.percentile_50 = function percentile(collection, accessor) {
|
|
807
|
+
return AggregateUtils.percentile(collection, accessor, 50);
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Returns a hard coded percentage
|
|
812
|
+
*
|
|
813
|
+
* {@link module:aggregate.percentage|See Percentage for more detail}
|
|
814
|
+
*
|
|
815
|
+
* @param {Object[]} collection - collection of objects
|
|
816
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
817
|
+
* @returns {Number} - the percentile of a property within the collection
|
|
818
|
+
* @see {@link module:aggregate.percentile|percentile} - as this simply hard codes the percentage
|
|
819
|
+
*/
|
|
820
|
+
module.exports.percentile_75 = function percentile(collection, accessor) {
|
|
821
|
+
return AggregateUtils.percentile(collection, accessor, 75);
|
|
822
|
+
};
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Returns a hard coded percentage
|
|
826
|
+
*
|
|
827
|
+
* {@link module:aggregate.percentage|See Percentage for more detail}
|
|
828
|
+
*
|
|
829
|
+
* @param {Object[]} collection - collection of objects
|
|
830
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
831
|
+
* @returns {Number} - the percentile of a property within the collection
|
|
832
|
+
* @see {@link module:aggregate.percentile|percentile} - as this simply hard codes the percentage
|
|
833
|
+
*/
|
|
834
|
+
module.exports.percentile_90 = function percentile(collection, accessor) {
|
|
835
|
+
return AggregateUtils.percentile(collection, accessor, 90);
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Returns a hard coded percentage
|
|
840
|
+
*
|
|
841
|
+
* {@link module:aggregate.percentage|See Percentage for more detail}
|
|
842
|
+
*
|
|
843
|
+
* @param {Object[]} collection - collection of objects
|
|
844
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
845
|
+
* @returns {Number} - the percentile of a property within the collection
|
|
846
|
+
* @see {@link module:aggregate.percentile|percentile} - as this simply hard codes the percentage
|
|
847
|
+
*/
|
|
848
|
+
module.exports.percentile_95 = function percentile(collection, accessor) {
|
|
849
|
+
return AggregateUtils.percentile(collection, accessor, 95);
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* Returns a hard coded percentage
|
|
854
|
+
*
|
|
855
|
+
* {@link module:aggregate.percentage|See Percentage for more detail}
|
|
856
|
+
*
|
|
857
|
+
* @param {Object[]} collection - collection of objects
|
|
858
|
+
* @param {Function | String} accessor - function to access the value, string property or null
|
|
859
|
+
* @returns {Number} - the percentile of a property within the collection
|
|
860
|
+
* @see {@link module:aggregate.percentile|percentile} - as this simply hard codes the percentage
|
|
861
|
+
*/
|
|
862
|
+
module.exports.percentile_99 = function percentile(collection, accessor) {
|
|
863
|
+
return AggregateUtils.percentile(collection, accessor, 99);
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* Returns the Top N values from within a collection.
|
|
868
|
+
*
|
|
869
|
+
* For example, if we have a list of weather records,
|
|
870
|
+
* we can get the month with the greatest rain.
|
|
871
|
+
*
|
|
872
|
+
* **Note: this can also return the Bottom N values, if sorting in ascending order.
|
|
873
|
+
* ({@link module:array.createSort|see array.createSort() for more.})**
|
|
874
|
+
*
|
|
875
|
+
* ```
|
|
876
|
+
* collection = [
|
|
877
|
+
* { id: 0, month: '2021-Sep', precip: 2.68 },
|
|
878
|
+
* { id: 1, month: '2021-Aug', precip: 0.87 },
|
|
879
|
+
* { id: 2, month: '2021-Oct', precip: 5.31 },
|
|
880
|
+
* { id: 3, month: '2021-Nov', precip: 3.94 },
|
|
881
|
+
* { id: 4, month: '2021-Dec', precip: 4.13 },
|
|
882
|
+
* { id: 5, month: '2022-Jan', precip: 3.58 },
|
|
883
|
+
* { id: 6, month: '2022-Feb', precip: 3.62 },
|
|
884
|
+
* { id: 7, month: '2022-Mar', precip: 3.98 },
|
|
885
|
+
* { id: 8, month: '2022-Apr', precip: 2.56 }
|
|
886
|
+
* ];
|
|
887
|
+
*
|
|
888
|
+
* //-- We can get the top 3 months with the highest rainfall
|
|
889
|
+
* utils.aggregate.topValues(collection, 3, 'month', '-precip');
|
|
890
|
+
* // '2021-Oct', '2021-Dec', '2022-Mar'
|
|
891
|
+
*
|
|
892
|
+
* //-- Or the 3 most recent precipitation values:
|
|
893
|
+
* utils.aggregate.topValues(collection, 3, 'precip', '-id');
|
|
894
|
+
* // 2.56, 3.98, 3.62
|
|
895
|
+
*
|
|
896
|
+
* //-- Lowest Rainfall is simply sorting in ascending order
|
|
897
|
+
* utils.aggregate.topValues(collection, 5, 'month', 'precip');
|
|
898
|
+
* // 0.87, 2.56, 2.68, 3.58, 3.62
|
|
899
|
+
*
|
|
900
|
+
* //-- you can also combine values to make the values clearer, by passing a function
|
|
901
|
+
* const monthPrecip = function (record) => `${record.month} (${record.precip})`;
|
|
902
|
+
* utils.aggregate.topValues(collection, 3, monthPrecip, '-precip');
|
|
903
|
+
* // '2021-Oct (5.31)', '2021-Dec (4.13)', '2022-Mar (3.98)'
|
|
904
|
+
* ```
|
|
905
|
+
*
|
|
906
|
+
* Literal values are also supported
|
|
907
|
+
*
|
|
908
|
+
* ```
|
|
909
|
+
* collection = [ 2.68, 0.87, 5.31, 3.94, 4.13, 3.58, 3.62, 3.98, 2.56 ];
|
|
910
|
+
*
|
|
911
|
+
* //-- top 5 values
|
|
912
|
+
* utils.aggregate.topValues(collection, 5);
|
|
913
|
+
* utils.aggregate.topValues(collection, 5, null, '-')
|
|
914
|
+
* // [5.31, 4.13, 3.98, 3.94, 3.62]
|
|
915
|
+
*
|
|
916
|
+
* //-- bottom 5 values
|
|
917
|
+
* utils.aggregate.topValues(collection, 5, null, '');
|
|
918
|
+
* //
|
|
919
|
+
* ```
|
|
920
|
+
*
|
|
921
|
+
* @param {Array} collection - Collection of values we want to get the top values from
|
|
922
|
+
* @param {Number} [numValues=5] - the number of values to return
|
|
923
|
+
* @param {string | Function} [fieldOrFn = null] - field of the object to use as the value, <br />
|
|
924
|
+
* Or the Function to generate the value, <br />
|
|
925
|
+
* Or null if the value is an array of Comparables (like Number)
|
|
926
|
+
* @param {...String} sortFields - field in the object to sort by,<br />
|
|
927
|
+
* Prefixed by '-' if it should be sorted in Descending order
|
|
928
|
+
* (ex: '-Year', 'Manufacturer')
|
|
929
|
+
* @returns {Array} - array of values
|
|
930
|
+
*/
|
|
931
|
+
module.exports.topValues = function topValues(collection, numValues = 5, fieldOrFn, ...sortFields) {
|
|
932
|
+
let cleanCollection = collection || [];
|
|
933
|
+
|
|
934
|
+
//-- if no sort fields are provided, sort in descending order
|
|
935
|
+
const cleanSortFields = sortFields.length === 0
|
|
936
|
+
? ['-']
|
|
937
|
+
: sortFields;
|
|
938
|
+
|
|
939
|
+
cleanCollection = cleanCollection.sort(
|
|
940
|
+
ArrayUtils.createSort(...cleanSortFields)
|
|
941
|
+
);
|
|
942
|
+
|
|
943
|
+
return AggregateUtils.property(
|
|
944
|
+
cleanCollection.slice(0, numValues),
|
|
945
|
+
fieldOrFn
|
|
946
|
+
);
|
|
947
|
+
};
|
package/src/format.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* * Formatting Strings
|
|
13
13
|
* * {@link module:format.capitalize|format.capitalize} - Capitalizes only the first character in the string (ex: 'John paul');
|
|
14
14
|
* * {@link module:format.capitalizeAll|format.capitalizeAll} - Capitalizes all the words in a string (ex: 'John Paul')
|
|
15
|
+
* * {@link module:format.ellipsify|format.ellipsify} - Truncates a string if the length is 'too long'
|
|
15
16
|
* * Formatting Time
|
|
16
17
|
* * {@link module:format.millisecondDuration|format.millisecondDuration}
|
|
17
18
|
* * Mapping Values
|
package/src/object.js
CHANGED
|
@@ -22,6 +22,7 @@ const schemaGenerator = require('generate-schema');
|
|
|
22
22
|
* * {@link module:object.fetchObjectProperties|fetchObjectProperties(object, string[])} - use dot notation to bring multiple child properties onto a parent
|
|
23
23
|
* * {@link module:object.join|join(array, index, map, fn)} - join a collection against a map by a given index
|
|
24
24
|
* * {@link module:object.joinProperties|join(array, index, map, ...fields)} - join a collection, and copy properties over from the mapped object.
|
|
25
|
+
* * {@link module:object.propertyFromList|propertyFromList(array, propertyName)} - fetches a specific property from all objects in a list
|
|
25
26
|
* * Rename properties
|
|
26
27
|
* * {@link module:object.cleanProperties|cleanProperties()} - correct inaccessible property names in a list of objects
|
|
27
28
|
* * {@link module:object.cleanPropertyNames|cleanPropertyNames()} - create a translation of inaccessible names to accessible ones
|
|
@@ -638,6 +639,40 @@ module.exports.joinProperties = function join(objectArray, indexField, targetMap
|
|
|
638
639
|
return ObjectUtils.join(objectArray, indexField, targetMap, joinFn);
|
|
639
640
|
};
|
|
640
641
|
|
|
642
|
+
/**
|
|
643
|
+
* Maps an array of values to a single property.
|
|
644
|
+
*
|
|
645
|
+
* For example:
|
|
646
|
+
*
|
|
647
|
+
* ```
|
|
648
|
+
* const data = [{ record: 'jobA', val: 1 }, { record: 'jobA', val: 2 },
|
|
649
|
+
* { record: 'jobA', val: 3 }, { record: 'jobA', val: 4 },
|
|
650
|
+
* { record: 'jobA', val: 5 }, { record: 'jobA', val: 6 },
|
|
651
|
+
* { record: 'jobA', val: 7 }, { record: 'jobA', val: 8 },
|
|
652
|
+
* { record: 'jobA', val: 9 }, { record: 'jobA', val: 10 }
|
|
653
|
+
* ];
|
|
654
|
+
*
|
|
655
|
+
* utils.object.propertyFromList(data, 'val')
|
|
656
|
+
* //-- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
657
|
+
*
|
|
658
|
+
* utils.object.propertyFromList(data, (r) => r.val);
|
|
659
|
+
* //-- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
660
|
+
* ```
|
|
661
|
+
*
|
|
662
|
+
* @param {Object[]} objectArray - Array of Objects to be mapped to a single property / value
|
|
663
|
+
* @param {Function | String} propertyOrFn - Name of the property or Function to return a value
|
|
664
|
+
* @returns {Array} - Array of values
|
|
665
|
+
*/
|
|
666
|
+
module.exports.propertyFromList = function propertyFromList(objectArray, propertyOrFn) {
|
|
667
|
+
const cleanArray = Array.isArray(objectArray)
|
|
668
|
+
? objectArray
|
|
669
|
+
: [];
|
|
670
|
+
|
|
671
|
+
const fn = ObjectUtils.evaluateFunctionOrProperty(propertyOrFn);
|
|
672
|
+
|
|
673
|
+
return cleanArray.map(fn);
|
|
674
|
+
};
|
|
675
|
+
|
|
641
676
|
/**
|
|
642
677
|
* Finds objects that do not have ALL the properties specified.
|
|
643
678
|
*
|