jupyter-ijavascript-utils 1.22.4 → 1.23.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 +11 -0
- package/Dockerfile +1 -1
- package/README.md +5 -5
- package/package.json +1 -1
- package/src/TableGenerator.js +108 -3
- package/src/format.js +48 -0
- package/src/group.js +9 -7
- package/src/vega.js +160 -0
package/DOCS.md
CHANGED
|
@@ -63,8 +63,19 @@ This is not intended to be the only way to accomplish many of these tasks, and a
|
|
|
63
63
|
|
|
64
64
|

|
|
65
65
|
|
|
66
|
+
## Running on Binder
|
|
67
|
+
|
|
68
|
+
[mybinder.org](https://mybinder.org/) is a great place to run a Jupyter Notebook online.
|
|
69
|
+
|
|
70
|
+
It means you can run Jupyter Notebooks with additional kernels without having to install anything,
|
|
71
|
+
and can try right in your browser.
|
|
72
|
+
|
|
73
|
+
Give it a try here:
|
|
74
|
+
[](https://mybinder.org/v2/gh/paulroth3d/jupyter-ijavascript-utils/main?labpath=example.ipynb)
|
|
75
|
+
|
|
66
76
|
## What's New
|
|
67
77
|
|
|
78
|
+
* 1.23 - add format.parseNumber and TableGenerator.styleColumn, align group.separateByFields to vega-lite fold transform
|
|
68
79
|
* 1.22 - make chain iJavaScript aware, but still able to work outside of Jupyter
|
|
69
80
|
* 1.21 - include {@link module:chain|chain} - simple monoid
|
|
70
81
|
* 1.20 - fix vega dependency
|
package/Dockerfile
CHANGED
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@ This is not intended to be the only way to accomplish many of these tasks, and a
|
|
|
55
55
|
|
|
56
56
|
# What's New
|
|
57
57
|
|
|
58
|
+
* 1.23 - add format.parseNumber and TableGenerator.styleColumn, align group.separateByFields to vega-lite fold transform
|
|
58
59
|
* 1.22 - make chain iJavaScript aware, but still able to work outside of Jupyter
|
|
59
60
|
* 1.21 - include chain - simple monoid
|
|
60
61
|
* 1.20 - fix vega dependency
|
|
@@ -104,14 +105,13 @@ Steps Overview:
|
|
|
104
105
|
|
|
105
106
|
## Running on Binder
|
|
106
107
|
|
|
107
|
-
!TODO
|
|
108
|
-
|
|
109
108
|
[mybinder.org](https://mybinder.org/) is a great place to run a Jupyter Notebook online.
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
It means you can run Jupyter Notebooks with additional kernels without having to install anything,
|
|
111
|
+
and can try right in your browser.
|
|
113
112
|
|
|
114
|
-
|
|
113
|
+
Give it a try here:
|
|
114
|
+
[](https://mybinder.org/v2/gh/paulroth3d/jupyter-ijavascript-utils/main?labpath=example.ipynb)
|
|
115
115
|
|
|
116
116
|
# For Example
|
|
117
117
|
|
package/package.json
CHANGED
package/src/TableGenerator.js
CHANGED
|
@@ -112,6 +112,7 @@ const { createSort } = require('./array');
|
|
|
112
112
|
* * style the table
|
|
113
113
|
* * {@link TableGenerator#styleTable|styleTable(string)} - css style for the table
|
|
114
114
|
* * {@link TableGenerator#styleHeader|styleHeader(string)} - css styles for the header row
|
|
115
|
+
* * {@link TableGenerator#styleColumn|styleColumn(object)} - Function to style cells based on the column
|
|
115
116
|
* * {@link TableGenerator#styleRow|styleRow(fn)} - Function to style rows
|
|
116
117
|
* * {@link TableGenerator#styleCell|styleCell(fn)} - Function to style cells
|
|
117
118
|
* * {@link TableGenerator#border|border(string)} - Apply a border to the table data cells
|
|
@@ -229,6 +230,12 @@ class TableGenerator {
|
|
|
229
230
|
*/
|
|
230
231
|
#styleRow = null;
|
|
231
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Style to apply at the column level
|
|
235
|
+
* @type {Function}
|
|
236
|
+
*/
|
|
237
|
+
#styleColumn = null;
|
|
238
|
+
|
|
232
239
|
/**
|
|
233
240
|
* Style to apply at the cell
|
|
234
241
|
* @type {Function}
|
|
@@ -287,6 +294,7 @@ class TableGenerator {
|
|
|
287
294
|
this.#styleTable = '';
|
|
288
295
|
this.#styleHeader = '';
|
|
289
296
|
this.#styleRow = null;
|
|
297
|
+
this.#styleColumn = null;
|
|
290
298
|
this.#styleCell = null;
|
|
291
299
|
this.#isTransposed = false;
|
|
292
300
|
}
|
|
@@ -386,6 +394,7 @@ class TableGenerator {
|
|
|
386
394
|
* As this adds additional CSS, the styling applied:
|
|
387
395
|
* * {@link TableGenerator#styleTable|to the whole table}
|
|
388
396
|
* * or {@link TableGenerator#styleRow|to the rows}
|
|
397
|
+
* * or {@link TableGenerator#styleColumn|to the column}
|
|
389
398
|
* * or {@link TableGenerator#styleCell|to the data cells} will be affected
|
|
390
399
|
*
|
|
391
400
|
* For example:
|
|
@@ -882,11 +891,99 @@ class TableGenerator {
|
|
|
882
891
|
return this;
|
|
883
892
|
}
|
|
884
893
|
|
|
894
|
+
/**
|
|
895
|
+
* Function that can apply a style to a given column
|
|
896
|
+
*
|
|
897
|
+
* (rowIndex, ({ columnHeader, columnIndex, record, row, rowIndex, value })) => string
|
|
898
|
+
*
|
|
899
|
+
* note: see {@link TableGenerator#styleCell} for another way to do style a cell.
|
|
900
|
+
*
|
|
901
|
+
* ```
|
|
902
|
+
* dataSet = [
|
|
903
|
+
* {reg: 'z', source: 'A', temp: 10},
|
|
904
|
+
* {reg: 'z', source: 'B', temp: 98},
|
|
905
|
+
* {reg: 'z', source: 'A', temp: 100}
|
|
906
|
+
* ];
|
|
907
|
+
*
|
|
908
|
+
* utils.table(dataSet)
|
|
909
|
+
* .styleColumn({
|
|
910
|
+
* //-- we want to make the background color of the color red, if the temp > 50
|
|
911
|
+
* temp: (temp) => temp > 50 ? 'background-color:pink' : '',
|
|
912
|
+
*
|
|
913
|
+
* //-- we want to make the source bold if the source is B
|
|
914
|
+
* source: (source) => source === 'B' ? 'font-weight:bold' : ''
|
|
915
|
+
* })
|
|
916
|
+
* .render();
|
|
917
|
+
* ```
|
|
918
|
+
* <table cellspacing="0px" >
|
|
919
|
+
* <tr ><th>reg</th><th>source</th><th>temp</th></tr>
|
|
920
|
+
* <tr ><td >z</td><td >A</td><td >10</td></tr>
|
|
921
|
+
* <tr ><td >z</td><td style="font-weight:bold;">B</td><td style="background-color:pink;">98</td></tr>
|
|
922
|
+
* <tr ><td >z</td><td >A</td><td style="background-color:pink;">100</td></tr>
|
|
923
|
+
* </table>
|
|
924
|
+
*
|
|
925
|
+
* Or you could style the cell based on information in other columns.
|
|
926
|
+
*
|
|
927
|
+
* ```
|
|
928
|
+
* dataSet = [
|
|
929
|
+
* {reg: 'z', source: 'A', tempFormat: 'c', temp: 42},
|
|
930
|
+
* {reg: 'z', source: 'B', tempFormat: 'f', temp: 98},
|
|
931
|
+
* {reg: 'z', source: 'A', tempFormat: 'f', temp: 100}
|
|
932
|
+
* ];
|
|
933
|
+
*
|
|
934
|
+
* utils.table(dataSet)
|
|
935
|
+
* .styleColumn({
|
|
936
|
+
* //-- we want to make the background color of the color red, if the temp > 50
|
|
937
|
+
* temp: (temp, { record }) => convertToKelvin(temp, record.tempFormat) > 283
|
|
938
|
+
* ? 'background-color:pink'
|
|
939
|
+
* : ''
|
|
940
|
+
* })
|
|
941
|
+
* .render();
|
|
942
|
+
* ```
|
|
943
|
+
*
|
|
944
|
+
* <table cellspacing="0px" >
|
|
945
|
+
* <tr ><th>reg</th><th>source</th><th>tempFormat</th><th>temp</th></tr>
|
|
946
|
+
* <tr ><td >z</td><td >A</td><td >c</td><td style="background-color:pink;">10</td></tr>
|
|
947
|
+
* <tr ><td >z</td><td >B</td><td >f</td><td style="background-color:pink;">98</td></tr>
|
|
948
|
+
* <tr ><td >z</td><td >A</td><td >f</td><td style="background-color:pink;">100</td></tr>
|
|
949
|
+
* </table>
|
|
950
|
+
*
|
|
951
|
+
* @param {object} styleObj - object with properties matching the column header label
|
|
952
|
+
* @param {function(value, contextObj)} styleObj.property - Function to evaluate for each row returning the inline css styles to apply.
|
|
953
|
+
*
|
|
954
|
+
* When it runs it will get passed the value and context,
|
|
955
|
+
* and should return the css inline styles to apply
|
|
956
|
+
*
|
|
957
|
+
* @param {any} styleObj.property.value - the value for a given row for that column
|
|
958
|
+
* @param {any} styleObj.property.context.value - destructured value of the cell
|
|
959
|
+
* @param {Number} styleObj.property.context.columnIndex - destructured 0 index column of the cell
|
|
960
|
+
* @param {Number} styleObj.property.context.rowIndex - destructured 0 index row of the cell
|
|
961
|
+
* @param {Array} styleObj.property.context.row - destructured full row provided
|
|
962
|
+
* @param {Array} styleObj.property.context.record - destructured original record
|
|
963
|
+
* @returns {TableGenerator} - chainable instance
|
|
964
|
+
*/
|
|
965
|
+
styleColumn(styleObj) {
|
|
966
|
+
if (!styleObj) {
|
|
967
|
+
this.#styleColumn = null;
|
|
968
|
+
return this;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
if (typeof styleObj !== 'object') {
|
|
972
|
+
throw Error('styleColumn(styleObj): expects an object with properties matching the column LABELs');
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
this.#styleColumn = styleObj;
|
|
976
|
+
|
|
977
|
+
return this;
|
|
978
|
+
}
|
|
979
|
+
|
|
885
980
|
/**
|
|
886
981
|
* Function that can apply a style to a given cell
|
|
887
982
|
*
|
|
888
983
|
* (value, columnIndex, rowIndex, row, record) => string
|
|
889
984
|
*
|
|
985
|
+
* Note: see {@link TableGenerator#styleColumn} for another way to do style a cell.
|
|
986
|
+
*
|
|
890
987
|
* ```
|
|
891
988
|
* dataSet = [
|
|
892
989
|
* { title:'row 0', a: 0.608, b: 0.351, c: 0.823, d: 0.206, e: 0.539 },
|
|
@@ -914,13 +1011,14 @@ class TableGenerator {
|
|
|
914
1011
|
* ```
|
|
915
1012
|
* 
|
|
916
1013
|
*
|
|
917
|
-
* @param {function(*):any} formatterFn - Translation function to apply to all cells.
|
|
918
1014
|
*
|
|
919
1015
|
* When it runs, you will receive a single parameter representing the current cell and row.
|
|
920
1016
|
*
|
|
921
1017
|
* Return what the new value should be.
|
|
1018
|
+
* @param {function(*):any} formatterFn - Translation function to apply to all cells.
|
|
922
1019
|
* @param {any} formatterFn.value - destructured value of the cell
|
|
923
1020
|
* @param {Number} formatterFn.columnIndex - destructured 0 index column of the cell
|
|
1021
|
+
* @param {Number} formatterFn.columnHeader - destructured header of the column
|
|
924
1022
|
* @param {Number} formatterFn.rowIndex - destructured 0 index row of the cell
|
|
925
1023
|
* @param {Array} formatterFn.row - destructured full row provided
|
|
926
1024
|
* @param {Array} formatterFn.record - destructured original record
|
|
@@ -1061,6 +1159,7 @@ class TableGenerator {
|
|
|
1061
1159
|
const styleTable = this.#styleTable;
|
|
1062
1160
|
const styleHeader = this.#styleHeader;
|
|
1063
1161
|
const styleRowFn = this.#styleRow;
|
|
1162
|
+
const styleColumnObj = this.#styleColumn;
|
|
1064
1163
|
const styleCellFn = this.#styleCell;
|
|
1065
1164
|
const printOptions = this.#printOptions;
|
|
1066
1165
|
const borderCSS = this.#borderCSS;
|
|
@@ -1099,14 +1198,20 @@ class TableGenerator {
|
|
|
1099
1198
|
|
|
1100
1199
|
return `<tr ${printInlineCSS(rowStyle)}>\n\t`
|
|
1101
1200
|
+ dataRow.map((value, columnIndex) => {
|
|
1201
|
+
const columnHeader = results.headers[columnIndex];
|
|
1102
1202
|
//-- style for the cell
|
|
1103
|
-
const
|
|
1203
|
+
const cellData = { value, columnIndex, columnHeader, rowIndex, row: dataRow, record };
|
|
1204
|
+
const cellStyle = !styleCellFn ? '' : styleCellFn(cellData);
|
|
1205
|
+
const columnStyle = !styleColumnObj || !styleColumnObj[columnHeader] || !typeof styleColumnObj[columnHeader] === 'function'
|
|
1206
|
+
? ''
|
|
1207
|
+
: styleColumnObj[columnHeader](value, cellData);
|
|
1104
1208
|
|
|
1105
1209
|
return `<td ${
|
|
1106
1210
|
printInlineCSS(
|
|
1107
1211
|
borderCSS,
|
|
1108
1212
|
//-- could be inline, but not as clear
|
|
1109
|
-
cellStyle
|
|
1213
|
+
cellStyle,
|
|
1214
|
+
columnStyle
|
|
1110
1215
|
)
|
|
1111
1216
|
}>${
|
|
1112
1217
|
cleanFn(value, printOptions)
|
package/src/format.js
CHANGED
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
* * {@link module:format.safeConvertFloat|format.safeConvertFloat} - converts a value to a Number (123.4), or uses a default for any error or NaN
|
|
30
30
|
* * {@link module:format.safeConvertInteger|format.safeConvertInteger} - converts a value to a Number (123), or uses a default for any error or NaN
|
|
31
31
|
* * {@link module:format.safeConvertBoolean|format.safeConvertBoolean} - converts a value to a boolean
|
|
32
|
+
* * Parsing values
|
|
33
|
+
* * {@link module:format.parseNumber|format.parseBoolean(val)} - converts a value to a boolean value
|
|
34
|
+
* * {@link module:format.parseNumber|format.parseNumber(val, locale)} - converts a value to a number
|
|
32
35
|
* * Identifying values
|
|
33
36
|
* * {@link module:format.isEmptyValue|format.isEmptyValue} - determine if a value is not 'empty'
|
|
34
37
|
*
|
|
@@ -877,6 +880,51 @@ module.exports.isBoolean = function isBoolean(val) {
|
|
|
877
880
|
|| val === 'true' || val === 'false';
|
|
878
881
|
};
|
|
879
882
|
|
|
883
|
+
FormatUtils.parseLocaleCache = new Map();
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* Parses a given number, based on a {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat|Intl.NumberFormat}
|
|
887
|
+
*
|
|
888
|
+
* If the locale is not passed (ex: 'fr-FR'), then 'en-US' is assumed
|
|
889
|
+
*
|
|
890
|
+
* @param {any} val - value to parse
|
|
891
|
+
* @returns {Number} - parsed number
|
|
892
|
+
* @example
|
|
893
|
+
*
|
|
894
|
+
* utils.format.parseNumber(10); // 10
|
|
895
|
+
* utils.format.parseNumber('10'); // 10
|
|
896
|
+
* utils.format.parseNumber('1,000'); // 1000
|
|
897
|
+
* utils.format.parseNumber('1,000.5'); // 1000.5
|
|
898
|
+
* utils.format.parseNumber('1,000', 'en-US'); // 1000
|
|
899
|
+
* utils.format.parseNumber('1,000.5', 'en-US'); // 1000.5
|
|
900
|
+
* utils.format.parseNumber('1 000', 'fr-FR'); // 1000
|
|
901
|
+
* utils.format.parseNumber('1 000,5', 'fr-FR'); // 1000.5
|
|
902
|
+
*/
|
|
903
|
+
module.exports.parseNumber = function parseNumber(val, locale = 'en-US') {
|
|
904
|
+
const valType = typeof val;
|
|
905
|
+
if (valType === 'number') {
|
|
906
|
+
return val;
|
|
907
|
+
} else if (valType === 'string') {
|
|
908
|
+
let separator;
|
|
909
|
+
if (FormatUtils.parseLocaleCache.has(locale)) {
|
|
910
|
+
separator = FormatUtils.parseLocaleCache.get(locale);
|
|
911
|
+
} else {
|
|
912
|
+
const example = Intl.NumberFormat(locale).format('1.1');
|
|
913
|
+
separator = example.charAt(1);
|
|
914
|
+
FormatUtils.parseLocaleCache.set(locale, separator);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
const cleanPattern = new RegExp(`[^-+0-9${separator}]`, 'g');
|
|
918
|
+
const cleaned = val.replace(cleanPattern, '');
|
|
919
|
+
const normalized = cleaned.replace(separator, '.');
|
|
920
|
+
|
|
921
|
+
return parseFloat(normalized);
|
|
922
|
+
} else if (!val) {
|
|
923
|
+
return val;
|
|
924
|
+
}
|
|
925
|
+
return parseFloat(val);
|
|
926
|
+
};
|
|
927
|
+
|
|
880
928
|
/**
|
|
881
929
|
* Narrows to only fromLine - toLine (inclusive) within a string.
|
|
882
930
|
*
|
package/src/group.js
CHANGED
|
@@ -215,6 +215,8 @@ module.exports.rollup = function rollup(collection, reducer, prop, ...fields) {
|
|
|
215
215
|
*
|
|
216
216
|
* The object generated by the function is then merged.
|
|
217
217
|
*
|
|
218
|
+
* See [vega-lite fold transform](https://vega.github.io/vega-lite/docs/fold.html)
|
|
219
|
+
*
|
|
218
220
|
* @example
|
|
219
221
|
* aggregateWeather = utils.group.by(weather, 'city')
|
|
220
222
|
* .reduce((group) => ({
|
|
@@ -235,12 +237,12 @@ module.exports.rollup = function rollup(collection, reducer, prop, ...fields) {
|
|
|
235
237
|
*
|
|
236
238
|
* //-- gives
|
|
237
239
|
* [
|
|
238
|
-
* { city: 'Seattle', min: 0.87, max: 5.31, avg: 2.953,
|
|
239
|
-
* { city: 'New York', min: 3.58, max: 4.13, avg: 3.883,
|
|
240
|
-
* { city: 'Chicago', min: 2.56, max: 3.98, avg: 3.387,
|
|
241
|
-
* { city: 'Seattle', min: 0.87, max: 5.31, avg: 2.953,
|
|
242
|
-
* { city: 'New York', min: 3.58, max: 4.13, avg: 3.883,
|
|
243
|
-
* { city: 'Chicago', min: 2.56, max: 3.98, avg: 3.387,
|
|
240
|
+
* { city: 'Seattle', min: 0.87, max: 5.31, avg: 2.953, key: 'min', value: 0.87 },
|
|
241
|
+
* { city: 'New York', min: 3.58, max: 4.13, avg: 3.883, key: 'min', value: 3.58 },
|
|
242
|
+
* { city: 'Chicago', min: 2.56, max: 3.98, avg: 3.387, key: 'min', value: 2.56 },
|
|
243
|
+
* { city: 'Seattle', min: 0.87, max: 5.31, avg: 2.953, key: 'max', value: 5.31 },
|
|
244
|
+
* { city: 'New York', min: 3.58, max: 4.13, avg: 3.883, key: 'max', value: 4.13 },
|
|
245
|
+
* { city: 'Chicago', min: 2.56, max: 3.98, avg: 3.387, key: 'max', value: 3.98},
|
|
244
246
|
* ...
|
|
245
247
|
* ]
|
|
246
248
|
*
|
|
@@ -256,7 +258,7 @@ module.exports.separateByFields = function separateByFields(collection, ...field
|
|
|
256
258
|
if (!fields || !Array.isArray(fields) || fields.length < 1) {
|
|
257
259
|
throw (Error('separateByFields: fields are expected'));
|
|
258
260
|
}
|
|
259
|
-
return fields.flatMap((field) => collection.map((obj) => ({ ...obj,
|
|
261
|
+
return fields.flatMap((field) => collection.map((obj) => ({ ...obj, key: field, value: obj[field] })));
|
|
260
262
|
};
|
|
261
263
|
|
|
262
264
|
/**
|
package/src/vega.js
CHANGED
|
@@ -8,6 +8,9 @@ const IJSUtils = require('./ijs');
|
|
|
8
8
|
/**
|
|
9
9
|
* Helper for working with [Vega-Lite](https://vega.github.io/vega-lite/) (and [Vega](https://vega.github.io/vega/)) within iJavaScript notebooks.
|
|
10
10
|
*
|
|
11
|
+
* * [Vega-Lite Example Gallery](https://vega.github.io/vega-lite/examples/)
|
|
12
|
+
* * [Vega Example Gallery](https://vega.github.io/vega/examples/)
|
|
13
|
+
*
|
|
11
14
|
* ([Vega-Lite-Api](https://vega.github.io/vega-lite-api/):
|
|
12
15
|
* creates -> [Vega-Lite JSON specifications](https://vega.github.io/vega-lite/tutorials/getting_started.html):
|
|
13
16
|
* creates -> [Vega charting specifications](https://vega.github.io/):
|
|
@@ -25,6 +28,39 @@ const IJSUtils = require('./ijs');
|
|
|
25
28
|
* * Rendering specifications through the Jupyter Lab mime-type
|
|
26
29
|
* * {@link module:vega.vegaMimeType|vega.vegaMimeType(Object | String)} - render the chart using the Vega mime-type (as png)
|
|
27
30
|
* * {@link module:vega.vegaLiteMimeType|vega.vegaLiteMimeType(Object | String)} - render the chart using the Vega-Lite mime-type (as png)
|
|
31
|
+
*
|
|
32
|
+
* For example, this is a very simple demonstration for writing a vega-lite chart (the simplest way to get started)
|
|
33
|
+
*
|
|
34
|
+
* ```
|
|
35
|
+
* simpleData = [{fruit:'Apples',yield:20,year:'2020'},{fruit:'Apples',yield:22,year:'2021'},
|
|
36
|
+
* {fruit:'Bananas',yield:15,year:'2020'},{fruit:'Bananas',yield:12,year:'2021'},
|
|
37
|
+
* {fruit:'Pears',yield:18,year:'2020'},{fruit:'Pears',yield:19,year:'2021'}];
|
|
38
|
+
*
|
|
39
|
+
* utils.vega.svg(
|
|
40
|
+
* // accept the reference to the vega-lite instance passed
|
|
41
|
+
* (vl) => vl
|
|
42
|
+
* // render as points
|
|
43
|
+
* .markPoint()
|
|
44
|
+
* // use simpleData as the data source
|
|
45
|
+
* .data(simpleData)
|
|
46
|
+
* // title
|
|
47
|
+
* .title('Fruit by Yield')
|
|
48
|
+
* .width(100)
|
|
49
|
+
* .encode(
|
|
50
|
+
* // define the x axis as the Qualitative / Numerical 'yield' property
|
|
51
|
+
* vl.y().fieldQ('yield'),
|
|
52
|
+
* // define the y axis as the Nominative / TextBased 'fruit' property
|
|
53
|
+
* vl.x().fieldN('fruit'),
|
|
54
|
+
* // define the color series based on the Qualitative / Numerical 'year' property
|
|
55
|
+
* vl.color().fieldN('year')
|
|
56
|
+
* )
|
|
57
|
+
* );
|
|
58
|
+
* ```
|
|
59
|
+
* 
|
|
60
|
+
*
|
|
61
|
+
* and with simple changes, convert it to a bar graph
|
|
62
|
+
*
|
|
63
|
+
* 
|
|
28
64
|
* -----
|
|
29
65
|
*
|
|
30
66
|
* * Check out the {@tutorial vegaLite1} tutorials
|
|
@@ -155,6 +191,7 @@ const IJSUtils = require('./ijs');
|
|
|
155
191
|
* "x": {"field": "Horsepower", "type": "quantitative"},
|
|
156
192
|
* "y": {"field": "Miles_per_Gallon", "type": "quantitative"},
|
|
157
193
|
* "color": {"field": "Origin", "type": "nominal"},
|
|
194
|
+
* //-- simply by adding the tooltip encoding here
|
|
158
195
|
* "tooltip": {"field": "Name", "type": "nominal"},
|
|
159
196
|
* "href": {"field": "url", "type": "nominal"}
|
|
160
197
|
* }
|
|
@@ -163,6 +200,129 @@ const IJSUtils = require('./ijs');
|
|
|
163
200
|
*
|
|
164
201
|
* 
|
|
165
202
|
*
|
|
203
|
+
* or through the vega lite
|
|
204
|
+
*
|
|
205
|
+
* ---
|
|
206
|
+
*
|
|
207
|
+
* # FAQ
|
|
208
|
+
*
|
|
209
|
+
* The following are a series of common questions / issues, put here for visibility.
|
|
210
|
+
*
|
|
211
|
+
* ## Passing Objects to vega-lite-api
|
|
212
|
+
*
|
|
213
|
+
* Note that there are some things that are not supported by the vega-lite-api <br />
|
|
214
|
+
* ([such as grouping](https://github.com/vega/vega-lite/issues/4703))
|
|
215
|
+
*
|
|
216
|
+
* This is only a problem with the vega-lite-api, as it writes the spec used for vega-lite
|
|
217
|
+
*
|
|
218
|
+
* In these cases, you can send an object within many of the methods,
|
|
219
|
+
* as it no longer needs to translate how that object should look.
|
|
220
|
+
*
|
|
221
|
+
* (like sending `mark( type:'bar')` instead of `.markBar()` - to allow for tooltips <br />
|
|
222
|
+
* or passing an object to encode to support grouping)
|
|
223
|
+
*
|
|
224
|
+
* ```
|
|
225
|
+
* simpleData = [{fruit:'Apples',yield:20,year:'2020'},{fruit:'Apples',yield:22,year:'2021'},
|
|
226
|
+
* {fruit:'Bananas',yield:15,year:'2020'},{fruit:'Bananas',yield:12,year:'2021'},
|
|
227
|
+
* {fruit:'Pears',yield:18,year:'2020'},{fruit:'Pears',yield:19,year:'2021'}];
|
|
228
|
+
*
|
|
229
|
+
* utils.vega.svg((vl) => vl
|
|
230
|
+
* // render as points
|
|
231
|
+
* .mark({ type: 'bar', tooltip: true})
|
|
232
|
+
* .data(simpleData)
|
|
233
|
+
* .title('Fruit by Yield')
|
|
234
|
+
* .width(100)
|
|
235
|
+
* .encode({
|
|
236
|
+
* "x": {"field": "fruit"},
|
|
237
|
+
* "y": {"field": "yield", "type": "quantitative"},
|
|
238
|
+
* "xOffset": {"field": "year"},
|
|
239
|
+
* "color": {"field": "year"}
|
|
240
|
+
* })
|
|
241
|
+
* );
|
|
242
|
+
* ```
|
|
243
|
+
*
|
|
244
|
+
* 
|
|
245
|
+
*
|
|
246
|
+
* ---
|
|
247
|
+
*
|
|
248
|
+
* ## Chart Series
|
|
249
|
+
*
|
|
250
|
+
* Instead of grouping values, you can also create a series of charts instead.
|
|
251
|
+
*
|
|
252
|
+
* ```
|
|
253
|
+
* utils.vega.svg((vl) => vl
|
|
254
|
+
* // render as points
|
|
255
|
+
* .mark({ type: 'arc', innerRadius: 30, tooltip: true})
|
|
256
|
+
* .data(simpleData)
|
|
257
|
+
* .title('Fruit by Yield')
|
|
258
|
+
* .width(100)
|
|
259
|
+
* .encode(
|
|
260
|
+
* // define the arc on the graph with the Qualitative / Numerical 'yield' property
|
|
261
|
+
* vl.theta().fieldQ('yield'),
|
|
262
|
+
* // define the y axis as the based on the Qualitative / Numerical 'year' property
|
|
263
|
+
* vl.color().fieldN('year'),
|
|
264
|
+
* // define the color series Nominative / TextBased 'fruit' property
|
|
265
|
+
* vl.column().fieldN('fruit')
|
|
266
|
+
* )
|
|
267
|
+
* );
|
|
268
|
+
* ```
|
|
269
|
+
*
|
|
270
|
+
* 
|
|
271
|
+
*
|
|
272
|
+
* Other examples can be found [under the vega-lite examples](https://vega.github.io/vega-lite/examples/#repeat--concatenation)
|
|
273
|
+
* and rendered with {@link vega.svgFromSpec|svgFromSpec} or {@link vega.ßembedFromSpec|embedFromSpec}
|
|
274
|
+
*
|
|
275
|
+
* ---
|
|
276
|
+
*
|
|
277
|
+
* ## Object Formatting / Conversion
|
|
278
|
+
*
|
|
279
|
+
* Note that vega-lite examples use data at the mark level:
|
|
280
|
+
*
|
|
281
|
+
* ```
|
|
282
|
+
* [{fruit:'Apples',yield:20,year:'2020'},{fruit:'Apples',yield:22,year:'2021'},
|
|
283
|
+
* {fruit:'Bananas',yield:15,year:'2020'},{fruit:'Bananas',yield:12,year:'2021'},
|
|
284
|
+
* {fruit:'Pears',yield:18,year:'2020'},{fruit:'Pears',yield:19,year:'2021'}];
|
|
285
|
+
* ```
|
|
286
|
+
*
|
|
287
|
+
* not at the series level:
|
|
288
|
+
*
|
|
289
|
+
* ```
|
|
290
|
+
* [{ year:'2020', apples:20, bananas:15, pears:18 },
|
|
291
|
+
* { year:'2021', apples:22, bananas:12, pears:19 }];
|
|
292
|
+
* ```
|
|
293
|
+
*
|
|
294
|
+
* If your data is at the series level, you can:
|
|
295
|
+
*
|
|
296
|
+
* * Transform the data with the {@link group#separateByFields|group.separateByFields}
|
|
297
|
+
* * or using the [vega-lite fold transform](https://vega.github.io/vega-lite/docs/fold.html)
|
|
298
|
+
*
|
|
299
|
+
* ```
|
|
300
|
+
* fruitSeriesData = [{ year:'2020', apples:20, bananas:15, pears:18 },
|
|
301
|
+
* { year:'2021', apples:22, bananas:12, pears:19 }];
|
|
302
|
+
*
|
|
303
|
+
* utils.vega.svg((vl) => vl
|
|
304
|
+
* .mark({ type: 'arc', innerRadius: 30, tooltip: true})
|
|
305
|
+
* .data(fruitSeriesData)
|
|
306
|
+
*
|
|
307
|
+
* //-- apples, bananas and pears will now be separate records
|
|
308
|
+
* //-- with the new `key` field as either 'apple', 'banana', or 'pears'
|
|
309
|
+
* //-- and the new `value` field storing the value of those fields.
|
|
310
|
+
* .transform([{ fold: ['apples', 'bananas', 'pears']}])
|
|
311
|
+
*
|
|
312
|
+
* .title('Fruit by Yield')
|
|
313
|
+
* .width(100)
|
|
314
|
+
* .encode(
|
|
315
|
+
* // define the arc on the graph with the Qualitative / Numerical 'yield' property
|
|
316
|
+
* vl.theta().fieldQ('value'),
|
|
317
|
+
* // define the y axis as the Nominative / TextBased 'fruit' property
|
|
318
|
+
* vl.color().fieldN('year'),
|
|
319
|
+
* // define the color series based on the Qualitative / Numerical 'year' property
|
|
320
|
+
* vl.column().fieldN('key')
|
|
321
|
+
* )
|
|
322
|
+
* )
|
|
323
|
+
* ```
|
|
324
|
+
* 
|
|
325
|
+
*
|
|
166
326
|
* ---
|
|
167
327
|
*
|
|
168
328
|
* For more:
|