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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more