Published
Edited
Aug 19, 2020
Insert cell
Insert cell
Insert cell
chart = {
// canvas
var svg = d3.create('svg').attr('viewBox', [0, 0, width, height]);

// axes
var xAxis = d3.axisTop(xScale)(
svg.append('g').attr('transform', `translate(${0},${margin.top})`)
);
var yAxis = d3.axisLeft(yScale)(
svg.append('g').attr('transform', `translate(${margin.left},${0})`)
);

// points
let visitIndex = 0;
let visit = visits[visitIndex];
var visitText = svg
.append('text')
.attr('x', margin.left)
.attr('dx', 4)
.attr('y', margin.top)
.attr('dy', 4)
.attr('alignment-baseline', 'hanging')
.text(visit);
measure.forEach(d => {
d.ARM = d[1][0].ARM;
d.datum = d[1].find(di => di.AVISIT === visits[visitIndex]);
d.pchg_bin = d.datum ? d.datum.pchg_bin : null;
});
var g = svg
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
var nodes = svg
.selectAll('circle')
.data(measure, d => d[0])
.join('circle')
.attr('r', radius)
.attr('fill', 'white')
.attr('stroke', d => colorScale(d.ARM));

var simulation = d3
.forceSimulation(measure)
.force('x', d3.forceX(d => xScale(d.pchg_bin) + xScale.bandwidth() / 2))
.force('y', d3.forceY(d => yScale(d.ARM) + yScale.bandwidth() / 2))
.force('collide', d3.forceCollide(radius));

simulation.on('tick', () => {
nodes
.filter(d => d.pchg_bin !== null)
.attr('cx', d => (d.x ? d.x : xScale(0) + xScale.bandwidth() / 2))
.attr('cy', d => (d.y ? d.y : yScale(d.ARM) + yScale.bandwidth() / 2));
//.attr('display', d => (d.x === 0 || !!d.x ? null : 'none'));
});

// d3.interval(() => {
// visitIndex++;
// if (visitIndex === visits.length) visitIndex = 0;
// visit = visits[visitIndex];
// visitText.text(visit);
// measure.forEach(d => {
// d.datum = d[1].find(di => di.AVISIT === visit);
// d.pchg_bin = d.datum ? d.datum.pchg_bin : null;
// });
// simulation
// .nodes(measure)
// .alpha(.1)
// .restart();
// }, 2500);

return svg.node();
}
Insert cell
yScale.bandwidth()
Insert cell
yScale = d3
.scaleBand()
.domain(groups)
.range([margin.top, height - margin.top - margin.bottom])
Insert cell
xScale.bandwidth()
Insert cell
xScale = d3
.scaleBand()
.domain(d3.range(-3, 4))
.range([margin.left, width - margin.left - margin.right])
Insert cell
colorScale = d3.scaleOrdinal()
.domain(groups)
.range(d3.schemeCategory10)
Insert cell
changeScale = d3
.scaleQuantize()
.domain([-100, 100])
.range(d3.range(-3, 4))
Insert cell
radius = 3
Insert cell
margin = ({ top: 30, right: 10, bottom: 10, left: 90 })
Insert cell
height = (width / 5) * groups.length
Insert cell
groups = [...new Set(data.map(d => d[group])).values()]
Insert cell
group = 'ARM'
Insert cell
measure = [...measures.get('Platelet count (x 109/L)').entries()]
Insert cell
// Calculate change from baseline
measures = d3.rollup(
data.filter(d => visits.includes(d.AVISIT)),
group => {
group.forEach((d, i) => {
d.baseline = group[0].AVAL;
d.chg = d.AVAL - d.baseline;
d.fchg = d.chg / d.baseline;
d.pchg = d.fchg * 100;
d.pchg_bin = changeScale(d.pchg);
});

return group;
},
d => d.PARAM,
d => d.USUBJID
)
Insert cell
visits = [
...new Set(
data.filter(d => !(d.AVISITN % 1)).map(d => d.AVISIT + '|' + d.AVISITN)
).values()
]
.sort((a, b) => a.replace(/.*\|/, '') - b.replace(/.*\|/, ''))
.map(value => value.replace(/\|.*$/, ''))
Insert cell
data = {
return (await d3.csv('https://raw.githubusercontent.com/RhoInc/data-library/master/data/clinical-trials/adam/adlb.csv', d3.autoType));
}
Insert cell
d3 = require('d3@5', 'd3-array@2')
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