Published
Edited
Oct 8, 2021
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require('d3@7')
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const ol = d3.create('ol');
ol.selectAll('li') // select all list elements (orange circle below)
.data(listData) // bind all our data values (blue circle below)
return ol.node(); // return the DOM element node of the 'ol' element
}
Insert cell
Insert cell
selection = {
const ol = d3.create('ol');
return ol.selectAll('li').data(listData);
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const ol = d3.create('ol');

ol.selectAll('li') // select all list elements (orange circle above)
.data(listData) // bind all our data values (blue circle above)
.join('li') // merge the 'enter' and 'update' sets, create 'li' elements as needed

return ol.node(); // return the DOM element node of the 'ol' element
}
Insert cell
Insert cell
vis = {
const ol = d3.create('ol');
ol.selectAll('li') // select all list elements (orange circle above)
.data(listData) // bind all our data values (blue circle above)
.join(
enter => enter.append('li'), // <-- append an li element for each entering item
update => update, // <-- do nothing with items that match an existing element
exit => exit.remove() // <-- remove li elements whose backing data is now gone
)
return ol.node(); // return the DOM element node of the 'ol' element
}
Insert cell
Insert cell
{
const ol = d3.create('ol');

ol.selectAll('li') // select all list elements (orange circle above)
.data(listData) // bind all our data values (blue circle above)
.join('li') // merge the 'enter' and 'update' sets, create 'li' elements as needed
.attr('class', 'country') // <-- set CSS class to 'country'
.text(d => `${d.country}: ${d.pop}`) // <-- add text to 'li' elements

return ol.node(); // return the DOM element node of the 'ol' element
}
Insert cell
Insert cell
// Run this cell to recolor just the first item in the list above
d3.select('li.country').style('color', randomColor()), null
Insert cell
// Run this cell to recolor ALL items in the list above
// Sets all items to the same randomly selected color
d3.selectAll('li.country').style('color', randomColor()), null
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const ol = d3.select('ol#enter-update-exit');

// use a new dataset, manipulable with the variables defined above
const newData = gapminder
.filter(d => d.year === year)
.sort((a, b) => b.pop - a.pop)
.slice(0, n);
ol.selectAll('li') // select all list elements
.data(newData, d => d.country) // bind our data values; what happens when we remove the key function?
.join(
enter => enter.append('li').style("color", "green"),
update => update.style("color", "blue"),
exit => exit.style("color", "red")
)
.text(d => `${d.country}: ${d.pop}`);
return newData;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
md`The current page \`width\` = ${width} px.` // Observable's built-in width property!
Insert cell
Insert cell
Insert cell
{
const container = d3.create('div');
const data = barData;
const barChart = container.selectAll('div')
/* TODO: Add code here to generate the bar chart within the container. */
.data(barData)
.join('div')
barChart
.style('background', 'steelblue') // Set the background color of the div to 'steelblue'
.style('border', '1px solid white') // Set the border of the div as 'white'
.style('font-size', 'small') // Set the text font size in the div to 'small'
.style('color', 'white') // Set the text font color to 'white'
.style('text-align', 'right') // Set the text alignment in the div to 'right'
.style('padding', '3px') // HINT: CSS styles require units, not just numbers
/* TODO: Add code here to finish updating the visual properties of the bars */
.style('width', d => `${xscale(d.value)}px`)
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
xscale = d3.scaleLinear()
.domain([0, d3.max(barData, d => d.value)])
.range([0, width]) // Observable's built-in width property!
Insert cell
Insert cell
xscale(49)
Insert cell
Insert cell
{
const container = d3.create('div');

container.selectAll('div')
.data(barData)
.join('div')
.style('background', 'steelblue')
.style('border', '1px solid white')
.style('font-size', 'small')
.style('color', 'white')
.style('text-align', 'right')
.style('padding', '3px')
.style('width', d => `${xscale(d.value)}px`) // <-- Use xscale instead of a magic number
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
color = d3.scaleOrdinal(d3.schemeTableau10).domain(barData.map(d => d.key));
// Default color schemes are here: https://github.com/d3/d3-scale-chromatic#categorical
// Try another one! For example: d3.schemePurples[6] or d3.schemePaired
Insert cell
{
const container = d3.create('div');

container.selectAll('div')
.data(barData)
.join('div')
.style('background', d => color(d.key)) // <-- Use color scale to specify the bar color
.style('border', '1px solid white')
.style('font-size', 'small')
.style('color', 'white')
.style('text-align', 'right')
.style('padding', '3px')
.style('width', d => `${xscale(d.value)}px`)
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
Insert cell
{
const barHeight = 25;
const height = barData.length * barHeight;

// create svg element, specify total width and height
const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

// add SVG 'rect' elements for bars
container.selectAll('rect')
.data(barData)
.join('rect')
.attr('x', 0)
.attr('y', (d, i) => i * barHeight)
.attr('width', d => xscale(d.value))
.attr('height', barHeight)
.style('fill', d => color(d.key))
.style('stroke', 'white');

// add SVG 'text' elements for labels
container.selectAll('text')
.data(barData)
.join('text')
.attr('x', d => xscale(d.value)) //here?
.attr('y', (d, i) => i * barHeight)
.attr('dx', -20)
.attr('dy', '1.25em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);

// return SVG DOM element
return container.node();
}
Insert cell
Insert cell
Insert cell
height = 150
Insert cell
yscale = d3.scaleBand()
.domain(barData.map(d => d.key))
.range([height, 0]) // Try flipping this to [height, 0] and see the effect on the bars below.
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

container.selectAll('rect')
.data(barData)
.join('rect')
.attr('x', 0)
.attr('y', d => yscale(d.key)) // <-- Use yscale instead of manually positioning bars
.attr('width', d => xscale(d.value))
.attr('height', yscale.bandwidth()) // <-- Band scales split a pixel range into equal-sized bands
.style('fill', d => color(d.key))
.style('stroke', 'white');

container.selectAll('text')
.data(barData)
.join('text')
.attr('x', d => xscale(d.value))
.attr('y', d => yscale(d.key)) // <-- Use yscale instead of manually positioning labels
.attr('dx', -20)
.attr('dy', '1.2em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const width = 400;
const height = 200;

const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

// Update the x scale here.
const xscale = d3.scaleBand()
.domain(barData.map(d => d.key))
.range([0, width]);
// Update the y scale here.
const yscale = d3.scaleLinear()
.domain([0, d3.max(barData, d => d.value)])
.range([0, height]);

container.selectAll('rect')
.data(barData)
.join('rect')
.attr('x', d => xscale(d.key)) // Update the x position
.attr('y', d => height - yscale(d.value)) // Update the y position
.attr('width', xscale.bandwidth()) // Update the width
.attr('height', d => yscale(d.value)) // Update the height
.style('fill', d => color(d.key))
.style('stroke', 'white');

container.selectAll('text')
.data(barData)
.join('text')
.attr('x', d => xscale(d.key)) // Update the x position
.attr('y', d => height - yscale(d.value)) // Update the y position
.attr('dx', 32) // Update the x offset
.attr('dy', '1.5em') // Update the y offset
.attr('fill', 'white')
.style('font-size', 'small')
.style('text-anchor', 'middle')
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
yscaleFixed = d3.scaleLinear()
.domain([0, d3.max(barData, d => d.value)])
.range([height, 0])
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

const xscale = d3.scaleLinear()
.domain([0, d3.max(barData, d => d.value)])
.range([0, width]);

const yscaleFixed = d3.scaleLinear()
.domain([0, d3.max(barData, d => d.value)])
.range([height, 0])
container.selectAll('rect')
.data(barData)
.join('rect')
.attr('x', 0)
.attr('y', d => yscale(d.key)) // <-- Use yscale instead of manually positioning bars
.attr('width', d => xscale(d.value))
.attr('height', yscale.bandwidth()) // <-- Band scales split a pixel range into equal-sized bands
.style('fill', d => color(d.key))
.style('stroke', 'white');

container.selectAll('text')
.data(barData)
.join('text')
.attr('x', d => xscale(d.value))
.attr('y', d => yscale(d.key)) // <-- Use yscale instead of manually positioning labels
.attr('dx', -20)
.attr('dy', '1.2em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

const g = container.selectAll('g')
.data(barData)
.enter() // <-- We use "enter" (not "join") so we can later append <rect> and <text> only for new data.
.append('g')
.attr('transform', d => `translate(0, ${yscale(d.key)})`);

g.append('rect')
// We no longer need to bind data to <rect>, or specify y positions.
.attr('width', d => xscale(d.value))
.attr('height', yscale.bandwidth())
.style('fill', d => color(d.key))
.style('stroke', 'white');

g.append('text')
// We no longer need to bind data to <text>, or specify y positions.
.attr('x', d => xscale(d.value))
.attr('dx', -20)
.attr('dy', '1.2em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);
return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
margin = ({top: 10, right: 10, bottom: 20, left: 20})
Insert cell
Insert cell
// Domain (data values): [0, 78], Range (pixel values): [20, width - 10]
xMargin = xscale.copy().range([margin.left, width - margin.right])
Insert cell
// Remember (0, 0) is the top-left hand corner; try flipping the elements and see what happens!
// Domain (data values): [0, 1, 2, 3, 4, 5], Range (pixel values): [height - 20, 10]
yMargin = yscale.copy().range([height - margin.bottom, margin.top])
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height)
.style('border', '1px dotted #999'); // <-- A dotted border helps us see the added margin

const g = container.selectAll('g')
.data(barData)
.enter()
.append('g')
.attr('transform', d => `translate(${margin.left}, ${yMargin(d.key)})`);

g.append('rect')
.attr('width', d => xMargin(d.value) - xMargin(0)) // <-- We must subtract our left offset.
.attr('height', yMargin.bandwidth())
.style('fill', d => color(d.key))
.style('stroke', 'white');

g.append('text')
.attr('x', d => xMargin(d.value) - xMargin(0)) // <-- We must subtract our left offset.
.attr('dx', -20)
.attr('dy', '1em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);

return container.node();
}
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height)
.style('border', '1px dotted #999');

container.append('g')
.attr('transform', `translate(0, ${height - margin.bottom})`)
.call(d3.axisBottom(xMargin));

container.append('g')
.attr('transform', `translate(${margin.left}, 0)`)
.call(d3.axisLeft(yMargin));

return container.node();
}
Insert cell
Insert cell
{
const container = d3.create('svg')
.attr('width', width)
.attr('height', height);

const g = container.selectAll('g')
.data(barData)
.enter()
.append('g')
.attr('transform', d => `translate(${margin.left}, ${yMargin(d.key)})`);

g.append('rect')
.attr('width', d => xMargin(d.value) - xMargin(0))
.attr('height', yMargin.bandwidth())
.style('fill', d => color(d.key))
.style('stroke', 'white');

g.append('text')
.attr('x', d => xMargin(d.value) - xMargin(0))
.attr('dx', -20)
.attr('dy', '1em')
.attr('fill', 'white')
.style('font-size', 'small')
.text(d => d.value);

container.append('g')
.attr('transform', `translate(0, ${height - margin.bottom})`)
.call(d3.axisBottom(xMargin));

container.append('g')
.attr('transform', `translate(${margin.left}, 0)`)
.call(d3.axisLeft(yMargin));

return container.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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