Public
Edited
Oct 18
54 forks
Importers
79 stars
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'),
update => update,
exit => exit.remove()
)
.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. */
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 */
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://d3js.org/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))
.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([0, height]) // 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.scaleLinear()
.domain([0, d3.max(barData, d => d.value)])
.range([0, width]);

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

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

container.selectAll('text')
.data(barData)
.join('text')
.attr('x', d => xscale(d.value)) // Update the x position
.attr('y', d => yscale(d.key)) // Update the y position
.attr('dx', -20) // 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
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

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