Published
Edited
Oct 12, 2019
1 star
Insert cell
Insert cell
md`## \`selection.join\`
Convenient and memorable API for joining data, similar to enter-append for a simple case`
Insert cell
{
const svg = d3.create('svg')
.attr('width', width)
.attr('height', 33)
.attr('viewBox', `0 -20 ${width} 33`)
svg.selectAll('text')
.data(randomLetters())
.join('text')
.attr('x', (d, i) => i * 16)
.text(d => d)
return svg.node()
}
Insert cell
md `But take the case of looping logic below: \`select.join\` can append entering elements and remove exiting elements to match data changes happening in the loop. The merged data set can then be subject to d3's chained operations.
Insert cell
{
const svg = d3.create('svg')
.attr('width', width)
.attr('height', 33)
.attr('viewBox', `0 -20 ${width} 33`)
while (true) {
svg.selectAll('text')
.data(randomLetters())
.join('text')
.attr('x', (d, i) => i * 16)
.text(d => d)
yield svg.node()
await Promises.tick(2500)
}
}
Insert cell
Insert cell
{
const svg = d3.create("svg")
.attr("width", width)
.attr("height", 33)
.attr("viewBox", `0 -20 ${width} 33`);

while (true) {
svg.selectAll("text")
.data(randomLetters(), d => d)
.join(
enter => enter.append('text')
.attr('fill', 'green')
.text(d => d),
update => update
.attr('fill', 'red')
)
.attr('x', (d, i) => i * 16)
yield svg.node()
await Promises.tick(2500)
}
}
Insert cell
md`Method chaining is necessary when creating transitions in d3. When Separate functions are passed to handle *enter, update, and exit* selections, use \`selection.call\` or return an undefined to prevent merging based on a return value. This keeps the method chain intact.`
Insert cell
{
const svg = d3.create("svg")
.attr("width", width)
.attr("height", 33)
.attr("viewBox", `0 -20 ${width} 33`);

while (true) {
const t = svg.transition()
.duration(750)
svg.selectAll("text")
.data(randomLetters(), d => d)
.join(
enter => enter.append('text')
.attr('fill', 'green')
.attr('x', (d, i) => i * 16)
.attr('y', -30)
.text(d => d)
.call(enter => enter.transition(t)
.attr('y', 0)),
update => update
.attr('fill', 'red')
.attr('y', 0)
.call(update => update.transition(t)
.attr('x', (d, i) => i * 16)),
exit => exit
.attr('fill', '#CCC')
.call(exit => exit.transition(t)
.attr('y', 30)
.remove())
)
yield svg.node()
await Promises.tick(2500)
}
}
Insert cell
md`# Depenedencies:`
Insert cell
d3 = require('d3')
Insert cell
width = 800
Insert cell
alphabet = "abcdefghijklmnopqrstuvwxyz".split("")
Insert cell
function randomLetters() {
return d3.shuffle(alphabet)
.slice(0, Math.floor(6 + Math.random() * 20))
.sort()
}
Insert cell
md`# Sources:
https://observablehq.com/@d3/selection-join`
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