Public
Edited
Apr 25, 2023
1 fork
Importers
3 stars
Color Legend
Pretty Tables
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
formatTable(SampleData)
Insert cell
SampleData = popByAgeGroupAndGender
Insert cell
Insert cell
formatTable(SampleData, [
{
path: "year",
title: "Year"
},
{
path: "census",
title: null, // Hide group title
props: [
{
path: "ageGroup",
title: "Age Group"
},
{
path: "populationByGender",
title: null, // Hide group title
props: [
{ path: "gender", title: "Gender" },
{ path: "population", title: "Population" }
]
}
]
}
])
Insert cell
Insert cell
formatTable(SampleData, null, {
height: 200, // Set height of the table,
width: "80%"
})
Insert cell
Insert cell
Insert cell
function formatTable(
data,
props, // See https://github.com/yetrun/json5-to-table#props%E5%AE%9A%E5%88%B6%E5%B5%8C%E5%A5%97%E5%B1%9E%E6%80%A7
opts = {}
) {
const options = Object.assign(
{
// Format Date data types. Use path to selectively format.
dateFormat: (datum, path) => isoformat.format(datum),

// Format all values. Use path to selectively format.
// 📝 dateFormat take precedence for Date types
format: (datum, path) => datum,

height: 274, // Set height of the table. Default is on the Inputs.table
width: null // Set width of the table.
},
opts
);

const minHeight = 33;
let { height, width } = options;
const copy = cleanseData(data, options);

height = height > minHeight ? height : null;

const generateHTMLTableoptions = {
attributes: {
table: {
// Based on Observable table styles
style: `
max-width: initial;
${minHeight != null ? `min-height: ${length(minHeight)};` : ""}
margin: 0;
border-spacing: 0;
font-variant-numeric: tabular-nums;`
},
th: {
style: `padding: 3px 6.5px; position: sticky; top: 0; background: #fff;`
},
td: {
style: `padding: 3px 6.5px`
}
}
};

return html`<div style="overflow-x: auto;${
height ? `max-height: ${height}px;` : ""
}${width != null ? `width: ${length(width)};` : ""}">
${json2table.generateHTMLTable(copy, props, generateHTMLTableoptions)}
</div>`;
}
Insert cell
function cleanseData(d, opts, path) {
function cleanseObject(o) {
const newObj = {};
for (const [k, v] of Object.entries(o)) {
const currentPath = path == null ? k : `${path}.${k}`;
newObj[cleanKey(k)] = cleanseData(v, opts, currentPath);
}
return newObj;
}

function cleanKey(k) {
return k.replaceAll(blacklistRegex, "_");
}

if (Array.isArray(d)) {
return d.map(cleanseObject);
}

if (isDate(d)) {
return typeof opts.dateFormat === "function"
? opts.dateFormat(d, path)
: d.toString();
}

if (isObject(d)) {
return cleanseObject(d);
}

return typeof opts.format === "function" ? opts.format(d, path) : d;
}
Insert cell
function isObject(a) {
// https://stackoverflow.com/a/8511350
return typeof a === "object" && !Array.isArray(a) && a !== null;
}
Insert cell
function isDate(value) {
return value instanceof Date;
}
Insert cell
// From https://github.com/observablehq/inputs/blob/main/src/css.js
function length(x) {
return x == null ? null : typeof x === "number" ? `${x}px` : `${x}`;
}
Insert cell
blacklistRegex = /(\.){1}/g
Insert cell
Insert cell
Insert cell
popByAgeGroupAndGender = {
let result = groupByArray(popByAgeGroupAndGenderRaw, "year", "census");

result = result.map((r) => {
return {
...r,
census: groupByArray(r.census, "ageGroup", "populationByGender")
};
});

return result;
}
Insert cell
function groupByArray(array, key, valueKey) {
let arr = Object.fromEntries(rollupByKey(array, key));

arr = Object.entries(arr).reduce((a, [k, value]) => {
return [
...a,
{
[key]: k,
[valueKey]: value
}
];
}, []);

return arr;
}
Insert cell
function rollupByKey(arr, key) {
let result = d3.rollup(
arr,
(d) => d,
(d) => d[key]
);

return result;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more