Published
Edited
Nov 23, 2019
Insert cell
md`# Random graphic with d3.join()
note: generator function can be used as timer in *ObservableHQ*`
Insert cell
dataLength=100
Insert cell
dataMax = 100
Insert cell
duration = 300
Insert cell
width = 500
Insert cell
height = 500
Insert cell
margin = 30
Insert cell
function randn_bm(min, max, skew) {
// creates distributed random
var u = 0, v = 0;
while(u === 0) u = Math.random(); //Converting [0,1) to (0,1)
while(v === 0) v = Math.random();
let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );

num = num / 10.0 + 0.5; // Translate to 0 -> 1
if (num > 1 || num < 0) num = randn_bm(min, max, skew); // resample between 0 and 1 if out of range
num = Math.pow(num, skew); // Skew
num *= max - min; // Stretch to fill range
num += min; // offset to min
return num;
}
Insert cell
createData = (_dataLength, _dataMax, _skew) => Array.from({length: _dataLength}).map(() => {
return Math.floor(randn_bm(0, _dataMax, _skew))
})
Insert cell
sampleDataset = {
let lists = [];
while (true) {
lists = createData(dataLength, dataMax, Math.random());
yield Promises.delay(duration, lists);
}
}
Insert cell
{
const svg = d3
.create('svg')
.attr('width', width)
.attr('height', height);
// window.svg.interrupt().selectAll('*').interrupt(); // remove older transitions. otherwise, memories leak and cause error.
const realWidth = width - margin * 2;
const realHeight = height - margin * 2;

while (true) {
const realDataset = createData(dataLength, dataMax, Math.random());

const gEnter = enter =>
enter
.append('rect')
.classed('bargraph', true)
.attr('fill', 'black')
.attr(
'transform',
(d, i) => `translate(${(i / dataLength) * realWidth},${realHeight})`
)
.attr('width', realWidth / dataLength)
.attr('height', 0)
.call(enter =>
enter
.transition(d3.easeLinear)
.duration(duration)
.attr(
'transform',
(d, i) =>
`translate(${(i / dataLength) * realWidth},${(d / dataMax) *
realHeight})`
)
.attr('height', (d, i) => (dataMax / d) * realHeight)
);

const gUpdate = update =>
update.call(update =>
update
.transition(d3.easeLinear)
.duration(duration)
.attr(
'transform',
(d, i) =>
`translate(${(i / dataLength) * realWidth},${(d / dataMax) *
realHeight})`
)
.attr('height', (d, i) => (dataMax / d) * realHeight)
);

const gExit = exit => exit.call(exit => exit.transition(duration).remove());

// d3 traces selector for tweened animation. give ID or CLASS in order to make animations work.
svg
.selectAll('.bargraph')
.data(realDataset)
.join(gEnter, gUpdate, gExit);
yield svg.node();
await Promises.tick(duration);
}
}
Insert cell
{
const svg = d3.create('svg')
.attr('width', width)
.attr('height', height)
// window.svg.interrupt().selectAll('*').interrupt(); // remove older transitions. otherwise, memories leak and cause error.
const realWidth = width - margin * 2
const realHeight = height - margin * 2
while(true) {
const realDataset = createData(dataLength, dataMax, Math.random() * 3);
const xScale = d3.scaleLinear().domain([0, dataLength]).range([0,realWidth]);
const yScale = d3.scaleLinear().domain([0, dataMax]).range([0,realHeight]);
const lineRenderer = d3.line().x((d, i) => xScale(i)).y(d => yScale(d));

const gEnter = enter => enter.append('path')
.classed('linegraph', true)
.attr('fill', 'transparent')
.attr('stroke', 'black')
.attr('stroke-width', 2)
.attr('transform', (d, i) => `translate(${margin},${margin})`)
.attr('d', lineRenderer)
const gUpdate = update => update.call(update => update.transition(d3.easeLinear)
.duration(duration)
.attr('d', lineRenderer)
);

const gExit = null;
// d3 traces selector for tweened animation. give ID or CLASS in order to make animations work.
svg.selectAll('.linegraph')
.data([realDataset]) // to be extended for multiple lines later
.join(gEnter, gUpdate, gExit)
yield svg.node();
await Promises.tick(duration);
}
}
Insert cell
_ = require('lodash');
Insert cell
d3 = require('d3');
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