Public
Edited
Mar 24, 2021
1 star
Insert cell
Insert cell
Insert cell
Insert cell
function barChart (data, accessor, labelAccessor) {
if (!accessor) {
accessor = (d) => d;
}
if (!labelAccessor) {
labelAccessor = (d) => '';
}
const labels = data.map(labelAccessor);
const values = data.map(accessor);
const max = Math.max(...values);
let extent = '<td></td>';
for (let i = 0; i < max; i++) {
extent += '<td></td>';
}
return html`
<style>
table.bar-chart tr {
border: none;
}
table.bar-chart .bar {
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
background-color: steelblue;
}
table.bar-chart .label {
width: 1px;
text-align: right;
padding-right: 8px;
}
</style>
<table class="bar-chart">
<tr>${extent}</tr>
${data.map(d => `
<tr style="height: 16px;">
<td class="label">${labelAccessor(d)}</td>
<td class="bar" colspan=${accessor(d)}></td>
<td>${accessor(d)}</td>
</tr>`).join('')}
</table>
`;
}
Insert cell
Insert cell
Insert cell
function lineChart(lineData, w, h)
{
const unitX = w / lineData.length;
const unitXSquared = unitX * unitX;
const maxVal = Math.max(...lineData);
const yScale = (d) => d * (h / maxVal);
function getWidth(y1, y2) {
return Math.sqrt(unitXSquared + Math.pow(y2 - y1, 2));
}
let prev = yScale(lineData[0]);
const angles = lineData.slice(1).map( (d, i) => {
const value = yScale(d);
const start = prev;
const angle = Math.atan2(prev - value, unitX);
const width = getWidth(value, prev);
prev = value;
const ret = { angle, width, value, start };
return ret;
});
return html`
<div style="display: flex; height: ${h}px; width: ${w}px; padding: 16px;">
<div style="border-right: 1px solid black; font-size: .75em; font-family: Arial;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
height: calc(100% + 10px)">
<div>${maxVal}</div>
<div>0</div>
</div>
<div style="position: relative; height: 100%; width: 100%; border-bottom: 1px solid black;">
${angles.map( (d, i) => {
return `<div style="
position: absolute;
left: 0;
top: 0;
box-sizing: border-box;
bottom: ${d.value}px;
width: ${d.width}px;
height: 1px;
transform-origin: left;
transform: translate(${i * unitX}px, ${h - d.start}px) rotate(${d.angle}rad);
border: 1px solid orange;
background: orange;"
></div>`
}).join('')
}
</div>
</div>
`
}
Insert cell
Insert cell
Insert cell
function scatterPlot (data, w, h) {
const pointSize = 5;
const maxY = Math.max(...data);
const scaleY = (d) => d * (h / maxY);
const unitX = w / data.length;
return html`<div style="height: ${h}px; width: ${w}px; display: flex; padding: 16px;">
<div style="border-right: 1px solid black; font-size: .75em; font-family: Arial;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
height: calc(100% + 10px)">
<div>${maxY}</div>
<div>0</div>
</div>
<div style="position: relative; height: 100%; border-bottom: 1px solid black; width: 100%;">
${data.map( (d, i) => `<div style="
transform: translate(${ i * unitX }px, ${ h - scaleY(d) }px);
position: absolute;
top: 0;
left: 0;
height: ${pointSize}px;
width: ${pointSize}px;
border-radius: ${pointSize}px;
background: steelblue;
border: 1px solid steelblue;"></div>`)}
</div>
</div>`
}
Insert cell
Insert cell
Insert cell
function histogram(data) {
const groupCount = data.reduce( (map, value) => {
if (map[value])
map[value]++;
else
map[value] = 1;
return map;
}, {});
const w = width;
const h = 200;
const itemWidth = Math.min(w / Object.keys(groupCount).length, 50);
const maxValue = Math.max(...Object.values(groupCount));
const yScale = (d) => d * h / maxValue;
return html`
<div style="display: flex;">
<div style="display: flex; flex-direction: column; margin-right: 2px;">
${new Array(maxValue).fill('').map( (val, i) =>
`<div style="position: relative; top: -9px; font-size: 0.75em; font-family: Arial; height: ${yScale(1)}px; box-sizing: border-box;">${maxValue - i}</div>`
)}
</div>
<div style="display: flex; flex-direction: column;">
${new Array(maxValue).fill('').map( (val, i) =>
`<div style="border-top: 1px solid grey; width: 4px; height: ${yScale(1)}px; box-sizing: border-box;"></div>`
)}
</div>
<div>
<div style="display: flex; align-items: flex-end;">
${Object.values(groupCount).map( val =>
`<div style="width: ${itemWidth}px; height: ${yScale(val)}px; border: 1px solid black; box-sizing: border-box; background: purple;"></div>`
).join('')}
</div>
<div style="display: flex; height: ${yScale(1)}px;">
${Object.keys(groupCount).map(key =>
`<div style="width: ${itemWidth}px; text-align: center;">${key}</div>`
).join('')}
</div>
</div>
</div>
`;
}
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