Skip to content

Instantly share code, notes, and snippets.

@paulroth3d
Last active June 10, 2021 03:28
Show Gist options
  • Save paulroth3d/246367cd407758657a44b6865d39a778 to your computer and use it in GitHub Desktop.
Save paulroth3d/246367cd407758657a44b6865d39a778 to your computer and use it in GitHub Desktop.

overview

Writes a table to html (such as for notebooks)

Examples

datasets = require('vega-datasets');

(async () => {
    cars = await datasets['cars.json']();
})();

$$.html(printTable(cars, {
    labels:{Miles_per_Gallon:'Miles per Gallon', Weight_in_lbs:'Weight in Lbs'},
    columnsToExclude: ['Cylinders'],
    sortFn: createSort('Name', '-Year'),
    // alternatively
    // sortFn: (a,b) => d3.ascending(a['Name'], b['Name']) || d3.ascending(a['Year'], b['Year'])
}));

Todo:

/**
* Creates a sorting function where the fields are sorted in ascending order by field names
* (note: prefixing the field with `-` beforehand makes the field sort in descending order)
* ex: cars.sort(createSort('Origin', '-Year', 'Name'))
**/
createSort = function() {
const fields = Array.from(arguments);
const simpleDescending = (a,b) => a==b ? 0 : a > b ? -1 : 1;
const simpleAscending = (a,b) => a==b ? 0 : a > b ? 1 : -1;
const sortFunctions = fields.map(field => {
if (field && field.length > 0) {
if (field[0] === '-') {
let newField = field.slice(1);
return ((a, b) => simpleDescending(a[newField], b[newField])); //d3.descending(a[newField], b[newField]));
} else {
return ((a, b) => simpleAscending(a[field], b[field])); //d3.ascending(a[field], b[field]));
}
}
});
return ((a, b) => {
for (let sortFunction of sortFunctions) {
let sortResult = sortFunction(a,b);
if (!sortResult) continue;
return sortResult;
}
})
};
printTable = (collection, options) => {
const cleanCollection = collection || [];
const cleanOptions = (options || {});
const {
/**
* Optional labels for columns by the property Name
* ex: {Miles_per_Gallon:'Miles per Gallon'} or {0:'Miles per Gallon'} for arrays
* @type {Object}
**/
labels = ({}),
/**
* Optional array of exclusive columns to show based on the properties of each row
* ex: ['Miles_per_Gallon', 'Name', 'Cylinders', etc]
* @type {String[]}
**/
columns = null,
/**
* Optional array of columns to not show based on the properties of the row
* ex: ['Serial_number']
* @type {String[]}
**/
columnsToExclude = [],
/**
* Sorting function
* ex: (a,b) => b['mpg'] - a['mpg']
* or alternatively multiple column sort
* ex: (a,b) => d3.ascending(a['mpg'], b['mpg']) || d3.descending(a['displacement'], b['displacement'])
* @type {Function}
**/
sortFn = null,
/**
* String style to apply to the table
* @ex: 'border: 1px solid black'
* @type {String}
**/
tableStyle = '',
/**
* Styles to apply to each row
* ex: 'border-bottom: 1px solid black'
* @type {String}
**/
rowStyle = ''
} = cleanOptions;
//-- get table info
const firstRow = cleanCollection[0];
//-- determine the columns to share
let keys = columns ? columns : Object.keys(firstRow);
//-- remove any columns if specified
keys = keys.filter((key) => columnsToExclude.indexOf(key) == -1);
const printHeaderLabel = (key) => {
if (labels.hasOwnProperty(key)) {
return labels[key];
}
return key;
}
const printValue = (val) => {
let valType = typeof val;
return !val ? null : (valType === 'string' || valType === 'number') ? val : JSON.stringify(val);
}
const valueFn = cleanOptions.valueFn || printValue;
const printHeader = (collection, keys) => `
<tr style='${rowStyle}'>
${keys.map(key => `<th>${printHeaderLabel(key)}</th>`).join('\n\t\t')}
</tr>`;
let printBody = () => (collection || [])
.map((row, index) => `\n<tr style="${rowStyle}">`
+ keys.map((key, keyIndex) =>
`<td>${valueFn(row[keys[keyIndex]])}</td>`
).join('\n\t')
+ '</tr>'
).join('\n');
const printTable = (collection, keys) => `<table style="${tableStyle}">`
+ printHeader(collection, keys)
+ printBody(collection)
+ '<table>';
//-- short circuit if no values are in collection
if (cleanCollection.length < 1) {
return `<table style='${tableStyle}'></table>`;
}
return printTable(sortFn ? collection.sort(sortFn) : collection, keys);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment