Public
Edited
Oct 9, 2024
9 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
barchart = {
const data = [
{ name: "questions", value: questions.length },
{ name: "schools", value: schools.length },
{ name: "philosophers", value: philosophers.length }
];
const w = 480;
const h = 300;
const m = 15;
const context = DOM.context2d(w + m * 2, h + m * 2);
const nameColor = {
questions: "#5B8FF9",
philosophers: "#61DDAA",
schools: "#65789B"
};
const [_, maxValue] = extent(data, (d) => d.value);

context.translate(m, m);

for (let i = 0; i < data.length; i++) {
const { name, value } = data[i];
const color = nameColor[name];
const step = w / data.length;
const x = step * i;
const width = step * 0.8;
const height = (h * 0.8 * value) / maxValue;
const y = h - 20 - height;

// draw bars
context.fillStyle = color;
context.fillRect(x, y, width, height);

// draw names
context.fillStyle = "black";
context.textAlign = "center";
context.textBaseline = "top";
context.font = "14px PingFangSC-Regular, sans-serif";
context.fillText(name, x + width / 2, y + height + 10);

// draw values
context.textBaseline = "middle";
context.fillStyle = "white";
context.font = "25px PingFangSC-Regular, sans-serif";
context.fillText(value, x + width / 2, y + height / 2);
}
return context.canvas;
}
Insert cell
Insert cell
Insert cell
Insert cell
scatter = {
// prepare data
const container = html`<div id="scatter-container"></div>`;
yield container;

const data = philosophers.map(d => ({
birthYear: +new Date(d.lifespan[0], 0, 1),
year: d.lifespan[1] - d.lifespan[0],
name: d.name
}));

// prepare canvas
const w = 600;
const h = 300;
const m = 50;
const canvas = new G.Canvas({
container,
width: w + m * 2,
height: h + m * 2
});

const [minBirth, maxBirth] = extent(data, d => d.birthYear);
const [minYear, maxYear] = extent(data, d => d.year);

// draw shapes
for (const { birthYear, year } of data) {
const x = m + ((birthYear - minBirth) / (maxBirth - minBirth)) * w;
const y = m + ((year - minYear) / (maxYear - minYear)) * h;

canvas.addShape('circle', {
attrs: {
x: x,
y: h + m * 2 - y,
r: 5,
fill: '#5B8FF9'
}
});
}

// draw xAxis
const xTicks = ticksByInterval(
year(yearCeil(minBirth, 200)),
year(yearFloor(maxBirth, 200)),
200
).map(d => +DateYear(d));

for (const tick of xTicks) {
const x = m + ((tick - minBirth) / (maxBirth - minBirth)) * w;
const y = h + m * 2 - 30;

canvas.addShape('line', {
attrs: {
x1: x,
x2: x,
y1: y - 5,
y2: y,
stroke: 'black'
}
});
canvas.addShape('text', {
attrs: {
text: `${year(tick)}`,
x: x,
y: y + 3,
stroke: 'black',
textAlign: 'center',
textBaseline: 'top',
fontSize: 10,
fontWeight: 'lighter'
}
});
}

// draw yAxis
const yTicks = ticksByInterval(
Math.ceil(minYear / 10) * 10,
Math.floor(maxYear / 10) * 10,
10
);

for (const tick of yTicks) {
const x = m - 15;
const y = h + m * 2 - (m + ((tick - minYear) / (maxYear - minYear)) * h);

canvas.addShape('line', {
attrs: {
x1: x - 5,
x2: x,
y1: y,
y2: y,
stroke: 'black'
}
});
canvas.addShape('text', {
attrs: {
text: tick,
x: x - 15,
y,
stroke: 'black',
textAlign: 'right',
textBaseline: 'middle',
fontSize: 10,
fontWeight: 'lighter'
}
});
}

function ticksByInterval(start, end, interval) {
const size = (((end - start) / interval) | 0) + 1;
return new Array(size).fill(0).map((_, i) => start + i * interval);
}

function yearCeil(timestamp, count) {
const y1 = year(timestamp);
const y2 = Math.ceil(y1 / count) * count;
return +DateYear(y2);
}

function yearFloor(timestamp, count) {
const y1 = year(timestamp);
const y2 = Math.floor(y1 / count) * count;
return +DateYear(y2);
}

function year(timestamp) {
return new Date(timestamp).getFullYear();
}

function DateYear(year) {
if (0 <= year && year < 100) {
const date = new Date(-1, 0, 1);
date.setFullYear(year);
return date;
}
return new Date(year, 0, 1);
}
}
Insert cell
Insert cell
Insert cell
Insert cell
pie = {
// prepare container
const container = html`<div id="pie-container"></div>`;
yield container;

const w = 300;
const h = 300;
const m = 50;
const canvas = new G.Canvas({
container,
width: w + m * 2,
height: h + m * 2
});

// prepare data with DataSet and Adjust
const ds = new DataSet();
const data = ds
.createView()
.source(schools)
.transform({
type: 'aggregate',
fields: ['type'],
operations: ['count'],
as: ['value'],
groupBy: ['type']
})
.rows.map(d => ({ type: d.type, value: d.value, key: 'pie' }));

const stack = new (Adjust.getAdjust('stack'))({
yField: 'value',
xField: 'pie'
});

const stackedData = stack
.process([data])[0]
.map(({ value, ...rest }) => ({ min: value[0], max: value[1], ...rest }));

const { min: minValue, max: maxValue } = ds
.createView()
.source(stackedData)
.transform({
type: 'aggregate',
fields: ['min', 'max'],
operations: ['min', 'max'],
as: ['min', 'max']
}).rows[0];

const types = ds
.createView()
.source(data)
.transform({
type: 'aggregate',
fields: ['type'],
as: ['count'],
groupBy: ['type'],
operations: ['count']
})
.rows.map(d => d.type);

// prepare scales with Scale
const color = new Scale.Ordinal({
domain: types,
range: colors
});

const x = new Scale.Linear({
domain: [minValue, maxValue],
range: [0, 1]
});

const y = new Scale.Band({
domain: ['pie'],
range: [0, 1]
});

// prepare coordinate by Coordinate
const polar = new Coord.Coordinate({
width: w,
height: h,
x: m,
y: m
})
.transform('translate', 0.5, 0.5)
.transform('reflect.y')
.transform('translate', -0.5, -0.5)
.transform('polar', 0, Math.PI * 2, 0, 1)
.transform('cartesian');

// draw arcs
for (const d of stackedData) {
const { key, type, min, max } = d;
const fill = color.map(type);
const l = max - min > (maxValue - minValue) / 2 ? 1 : 0;
const [p0, p1] = [[min, key], [max, key]].map(([dx, dy]) =>
polar.map([x.map(dx), y.map(dy)])
);

const cx = m + w / 2;
const cy = m + h / 2;
const r = w / 2;
canvas.addShape('path', {
attrs: {
fill,
path: [
['M', cx, cy],
['L', p0[0], p0[1]],
['A', r, r, 0, l, 1, p1[0], p1[1]],
['L', cx, cy],
['Z']
]
}
});
}

// draw legend
const ty = new Scale.Band({
domain: types,
range: [0, 50],
padding: 0.4
});
for (const t of types) {
const y = ty.map(t);
const x = w - 20;
const fill = color.map(t);
const size = ty.getBandWidth();
canvas.addShape('rect', {
attrs: {
fill,
x,
y,
width: size,
height: size
}
});
canvas.addShape('text', {
attrs: {
fill: 'black',
text: t,
x: x + size + 5,
y: y + size / 2,
textAlign: 'left',
textBaseline: 'middle'
}
});
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
wordCloud = {
const { Chart, registerShape, Util } = G2;

registerWordCloud(registerShape, Util);

// prepare for canvas
const container = html`<div id="wordcloud-container"></div>`;
yield container;

const w = 800;
const h = 400;
const chart = new Chart({
container,
autoFit: false,
width: w,
height: h,
padding: 0
});
const data = getWordCloudData(w, h);

chart.data(data);
chart.legend(false);
chart.axis(false);
chart.tooltip({
showTitle: false,
showMarkers: false
});
chart.coordinate().reflect();
chart
.point()
.position("x*y")
.color("title", colors)
.shape("cloud")
.tooltip("title");

chart.interaction("element-active");
chart.render();
}
Insert cell
Insert cell
Insert cell
Insert cell
forceGraph = {
const container = html`<div id="forcegraph-container"></div>`;
yield container;

const height = 450;
const width = 600;
const graph = new G6.Graph({
container: container,
width,
height,
layout: {
type: 'force',
preventOverlap: true,
linkDistance: d => (d.source.id === 'center' ? 100 : 50),
nodeStrength: d => (d.type === 'p' ? -50 : -30),
edgeStrength: d => (d.source.type === 'q' ? 0.7 : 0.1)
},
defaultNode: {
color: '#5B8FF9'
},
modes: {
default: [
'drag-node',
'drag-canvas',
{
type: 'tooltip',
formatText: d =>
`<div style='background: white; padding: 0.5em;border: 1px solid black'>
${d.name || d.title}
</div>`,
shouldUpdate: d => true
}
]
}
});

const data = getForceGraphData();
const nodes = data.nodes;
console.log(data);
graph.data({
nodes,
edges: data.edges.map((edge, i) => ({ ...edge, id: 'edge' + i }))
});
graph.render();

graph.on('node:dragstart', e => {
graph.layout();
refreshDragedNodePosition(e);
});
graph.on('node:drag', e => {
refreshDragedNodePosition(e);
});
graph.on('node:dragend', e => {
e.item.get('model').fx = null;
e.item.get('model').fy = null;
});

function refreshDragedNodePosition(e) {
const model = e.item.get('model');
model.fx = e.x;
model.fy = e.y;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
circlePacking = {
const container = html`<div id="circlepacking-container"></div>`;
yield container;

const plot = new G2Plot.CirclePacking(container, {
width: 600,
height: 600,
appendPadding: 30,
autoFit: true,
padding: 0,
data: getCirclePackingData(),
colorField: 'r',
color: 'rgb(252, 253, 191)-rgb(231, 82, 99)-rgb(183, 55, 121)',
pointStyle: {
stroke: 'rgb(183, 55, 121)',
lineWidth: 0.5
},
label: {
formatter: d => {
return d.children.length === 0 ? format(d.name) : '';
},
offsetY: 10,
style: {
fontSize: 12,
textAlign: 'center',
fill: 'rgba(0,0,0,0.65)'
}
},
hierarchyConfig: {
padding: 0.01
},
legend: false
});

plot.render();
}
Insert cell
Insert cell
Insert cell
Insert cell
AVAChart = {
const container = html`<div style="height: 500px;"></div>`;
yield container;
AVA.autoChart(container, getAVAData());
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
getCirclePackingData()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Adjust = import("@antv/adjust")
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