Published
Edited
Mar 11, 2019
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const graph = d3.select(DOM.svg(width, height));
const data = getRandomDataset();
const barPadding = 1;
graph.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => i * (width / data.length))
.attr("y", d => height - d * 4)
.attr("width", width / data.length - barPadding)
.attr("height", d => d * 4)
.attr("fill", d => d3.lab(40 + 2 * d, 100, -60));
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => d)
.attr("x", (d, i) => i * (width / data.length) + (width / data.length - barPadding) / 2)
.attr("y", d => height - d * 4 + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const graph = d3.select(DOM.svg(width, height));
const data = getRandomDataset();
const barPadding = 1;
const xScale = d3.scaleBand() // use an ordinal scale
.domain(d3.range(data.length)) // generate array from 0 to length in steps of 1
.rangeRound([0, width]) // output between 0 and width
.paddingInner(0.05); // % of whitespace between bars
const yScale = d3.scaleLinear() // basic linear scale for bar lengths
.domain([0, d3.max(data)])
.range([0, height]);
const cScale = d3.scaleSequential() // use a sequential scale with interpolator for the colors
.interpolator(d3.interpolateGreens)
.domain([0, d3.max(data)]);
graph.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i)) // use the scale to calculate x values
.attr("y", d => height - yScale(d))
.attr("width", xScale.bandwidth()) // use bandwidth of scale to determine bar width
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d)); // color scale
graph.selectAll("text")
.data(data)
.enter()
.append("text")
.text(d => d)
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(d) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 15, left: 0, right: 0, bottom: 0}; // add some padding
const graph = d3.select(DOM.svg(width, height));
graph.append("text") // add a label to click on
.attr("y", padding.top)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
const data = getRandomDataset();
const barPadding = 1;
const xScale = d3.scaleBand()
.domain(d3.range(data.length))
.rangeRound([padding.left, width - padding.right])
.paddingInner(0.05);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([padding.bottom, height - padding.top]);
const cScale = d3.scaleSequential()
.interpolator(d3.interpolateGreens)
.domain([0, d3.max(data)]);
graph.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(d))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d));
graph.selectAll("text.label")
.data(data)
.enter()
.append("text")
.attr("class", "label") // we added a class to be able to select them later
.text(d => d)
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(d) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
function updateData() { // for now, log to the console
console.log("update data");
}
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 15, left: 0, right: 0, bottom: 0};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomDataset();
const barPadding = 1;
const xScale = d3.scaleBand()
.domain(d3.range(data.length))
.rangeRound([padding.left, width - padding.right])
.paddingInner(0.05);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([padding.bottom, height - padding.top]);
const cScale = d3.scaleSequential()
.interpolator(d3.interpolateGreens)
.domain([0, d3.max(data)]);
graph.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(d))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d));
graph.selectAll("text.label")
.data(data)
.enter()
.append("text")
.attr("class", "label")
.text(d => d)
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(d) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
function updateData() {
data = getRandomDataset(); // generate new data
graph.selectAll("rect") // select all rects
.data(data) // bind the new data
.attr("y", d => height - yScale(d)) // update the attrs
.attr("height", d => yScale(d));
// notice that we have no enter or append call
}
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 15, left: 0, right: 0, bottom: 0};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomDataset();
const barPadding = 1;
const xScale = d3.scaleBand()
.domain(d3.range(data.length))
.rangeRound([padding.left, width - padding.right])
.paddingInner(0.05);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([padding.bottom, height - padding.top]);
const cScale = d3.scaleSequential()
.interpolator(d3.interpolateGreens)
.domain([0, d3.max(data)]);
graph.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(d))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d));
graph.selectAll("text.label")
.data(data)
.enter()
.append("text")
.attr("class", "label")
.text(d => d)
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(d) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
function updateData() {
data = getRandomDataset();
graph.selectAll("rect")
.data(data)
.transition() // magic interpolation
.duration(2000)
.attr("y", d => height - yScale(d))
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d)); // also update the color
graph.selectAll("text.label") // update the label position and values
.data(data)
.text(d => d)
.attr("y", d => height - yScale(d) + 15);
}
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 15, left: 0, right: 0, bottom: 0};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomDataset();
const barPadding = 1;
const xScale = d3.scaleBand()
.domain(d3.range(data.length))
.rangeRound([padding.left, width - padding.right])
.paddingInner(0.05);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([padding.bottom, height - padding.top]);
const cScale = d3.scaleSequential()
.interpolator(d3.interpolateGreens)
.domain([0, d3.max(data)]);
graph.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(d))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d));
graph.selectAll("text.label")
.data(data)
.enter()
.append("text")
.attr("class", "label")
.text(d => d)
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(d) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
function updateData() {
data = getRandomDataset();
graph.selectAll("rect")
.data(data)
.transition()
.delay((d,i) => i * 50) // delay the transition based on the position
.attr("y", d => height - yScale(d))
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d));
graph.selectAll("text.label")
.data(data)
.transition() // apply the same transition to the labels
.delay((d,i) => i * 50)
.text(d => d)
.attr("y", d => height - yScale(d) + 15);
}
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 15, left: 0, right: 0, bottom: 0};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomDataset();
const barPadding = 1;
const xScale = d3.scaleBand()
.domain(d3.range(data.length))
.rangeRound([padding.left, width - padding.right])
.paddingInner(0.05);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([padding.bottom, height - padding.top]);
const cScale = d3.scaleSequential()
.interpolator(d3.interpolateGreens)
.domain([0, d3.max(data)]);
graph.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(d))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d));
graph.selectAll("text.label")
.data(data)
.enter()
.append("text")
.attr("class", "label")
.text(d => d)
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(d) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
function updateData() {
data = getRandomDataset(25, 40);
// update the scales
yScale.domain([0, d3.max(data)]);
cScale.domain([0, d3.max(data)]);
graph.selectAll("rect")
.data(data)
.transition()
.delay((d,i) => i * 50)
.attr("y", d => height - yScale(d))
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d));
graph.selectAll("text.label")
.data(data)
.transition()
.delay((d,i) => i * 50)
.text(d => d)
.attr("y", d => height - yScale(d) + 15);
}
return graph.node();
}
Insert cell
Insert cell
Insert cell
{
const width = 500;
const height = 300;
const padding = {top: 20, left: 30, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
graph.append("text") // text to trigger update
.attr("y", padding.top - 3)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomScatterDataset();
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]);
const xAxis = d3.axisBottom()
.scale(xScale);
const yAxis = d3.axisLeft() // add a y-axis
.scale(yScale);
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", 2);
graph.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height - padding.bottom})`)
.call(xAxis);
graph.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${padding.left}, 0)`)
.call(yAxis);
function updateData() { // update the data using a transition
data = getRandomScatterDataset(25, 500);
graph.selectAll("circle")
.data(data)
.transition()
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]));
}
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 300;
const padding = {top: 20, left: 30, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top - 3)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomScatterDataset();
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]);
const xAxis = d3.axisBottom()
.scale(xScale);
const yAxis = d3.axisLeft()
.scale(yScale);
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", 2);
graph.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height - padding.bottom})`)
.call(xAxis);
graph.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${padding.left}, 0)`)
.call(yAxis);
function updateData() {
data = getRandomScatterDataset(25, 500);
//update the scales
xScale.domain([0, d3.max(data, d => d[0])]);
yScale.domain([0, d3.max(data, d => d[1])]);
graph.selectAll("circle")
.data(data)
.transition()
.on("start", function () { // use function instead of => because we need "this"
d3.select(this) // use the on function to do additional stuff at the start or end
.attr("fill", "hotpink")
.attr("r", 5);
})
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.on("end", function () { // after the transition, restore the dots to their original form
d3.select(this)
.attr("fill", "black")
.attr("r", 2);
});
graph.select(".x.axis") // select the x-axis and call the axis function again
.transition()
.call(xAxis);
graph.select(".y.axis") // and the same for the y-axis
.transition()
.call(yAxis);
}
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 300;
const padding = {top: 20, left: 30, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top - 3)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomScatterDataset();
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]);
const xAxis = d3.axisBottom()
.scale(xScale);
const yAxis = d3.axisLeft() // add a y-axis
.scale(yScale);
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", 2);
graph.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height - padding.bottom})`)
.call(xAxis);
graph.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${padding.left}, 0)`)
.call(yAxis);
function updateData() {
data.push(...getRandomScatterDataset(25, 500)); // append new data
xScale.domain([0, d3.max(data, d => d[0])]);
yScale.domain([0, d3.max(data, d => d[1])]);
graph.selectAll("circle")
.data(data)
.transition()
.on("start", function () {
d3.select(this)
.attr("fill", "hotpink")
.attr("r", 5);
})
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.on("end", function () {
d3.select(this)
.attr("fill", "black")
.attr("r", 2);
});
graph.select(".x.axis")
.transition()
.call(xAxis);
graph.select(".y.axis")
.transition()
.call(yAxis);
}
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 300;
const padding = {top: 20, left: 30, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top - 3)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomScatterDataset();
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]);
const xAxis = d3.axisBottom()
.scale(xScale);
const yAxis = d3.axisLeft()
.scale(yScale);
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", 2);
graph.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height - padding.bottom})`)
.call(xAxis);
graph.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${padding.left}, 0)`)
.call(yAxis);
function updateData() {
data.push(...getRandomScatterDataset(25, 500));
xScale.domain([0, d3.max(data, d => d[0])]);
yScale.domain([0, d3.max(data, d => d[1])]);
let circles = graph.selectAll("circle").data(data);
circles.enter() // add new circles for new data points
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", 2);
circles.transition() // next, update the existing circles
.on("start", function () {
d3.select(this)
.attr("fill", "hotpink")
.attr("r", 5);
})
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.on("end", function () {
d3.select(this)
.attr("fill", "black")
.attr("r", 2);
});
graph.select(".x.axis")
.transition()
.call(xAxis);
graph.select(".y.axis")
.transition()
.call(yAxis);
}
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 300;
const padding = {top: 20, left: 30, right: 40, bottom: 20};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top - 3)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomScatterDataset();
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[0])])
.range([padding.left, width - padding.right]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([height - padding.bottom, padding.top]);
const xAxis = d3.axisBottom()
.scale(xScale);
const yAxis = d3.axisLeft()
.scale(yScale);
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", 2);
graph.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height - padding.bottom})`)
.call(xAxis);
graph.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${padding.left}, 0)`)
.call(yAxis);
function updateData() {
data.push(...getRandomScatterDataset(25, 500));
data.shift();
xScale.domain([0, d3.max(data, d => d[0])]);
yScale.domain([0, d3.max(data, d => d[1])]);
let circles = graph.selectAll("circle").data(data);
circles.enter()
.append("circle")
.attr("cx", d => xScale(0)) // position the new data points in the origin
.attr("cy", d => yScale(0))
.attr("r", 2)
.merge(circles) // merge the existing circles with the new ones
.transition() // and transition everything to their new position
.on("start", function () {
d3.select(this)
.attr("fill", "hotpink")
.attr("r", 5);
})
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.on("end", function () {
d3.select(this)
.attr("fill", "black")
.attr("r", 2);
});
graph.select(".x.axis")
.transition()
.call(xAxis);
graph.select(".y.axis")
.transition()
.call(yAxis);
}
return graph.node();
}
Insert cell
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 15, left: 0, right: 0, bottom: 0};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getRandomDataset();
const barPadding = 1;
const xScale = d3.scaleBand()
.domain(d3.range(data.length))
.rangeRound([padding.left, width - padding.right])
.paddingInner(0.05);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([padding.bottom, height - padding.top]);
const cScale = d3.scaleSequential()
.interpolator(d3.interpolateGreens)
.domain([0, d3.max(data)]);
graph.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(d))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d));
graph.selectAll("text.label")
.data(data)
.enter()
.append("text")
.attr("class", "label")
.text(d => d)
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(d) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
function updateData() {
data.push(...getRandomDataset(1, 40)); // add one new data point
data.shift(); // and remove the first one
// update the scales
yScale.domain([0, d3.max(data)]);
cScale.domain([0, d3.max(data)]);
// update the bars
graph.selectAll("rect")
.data(data)
.transition()
.attr("y", d => height - yScale(d))
.attr("height", d => yScale(d))
.attr("fill", d => cScale(d));
// update the labels
graph.selectAll("text.label")
.data(data)
.transition()
.text(d => d)
.attr("y", d => height - yScale(d) + 15);
}
return graph.node();
}
Insert cell
Insert cell
function getIndexedRandomDataset(start = 0, size = 25, range = 20) {
const data = [];
for (let i = 0; i < size; i++) {
data.push([++start, 5 + Math.floor(Math.random() * range)]);
}
return data;
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 15, left: 0, right: 0, bottom: 0};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getIndexedRandomDataset(); // call new function
const barPadding = 1;
const xScale = d3.scaleBand()
.domain(d3.range(data.length))
.rangeRound([padding.left, width - padding.right])
.paddingInner(0.05);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])]) // use d[1] instead of d
.range([padding.bottom, height - padding.top]);
const cScale = d3.scaleSequential()
.interpolator(d3.interpolateGreens)
.domain([0, d3.max(data, d => d[1])]);
graph.selectAll("rect")
.data(data, d => d[0]) // here we specify our identifier, d[0]
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(d[1])) // point to d[1] instead of d
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(d[1]))
.attr("fill", d => cScale(d[1]));
graph.selectAll("text.label")
.data(data)
.enter()
.append("text")
.attr("class", "label")
.text(d => d[1])
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(d[1]) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
function updateData() {
data.push(...getIndexedRandomDataset(data[data.length - 1][0], 1, 40));
data.shift();
// update the scales
yScale.domain([0, d3.max(data, d => d[1])]);
cScale.domain([0, d3.max(data, d => d[1])]);
let bars = graph.selectAll("rect")
.data(data, d => d[0]);
bars.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(0))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(0))
.attr("fill", d => cScale(d[1]))
.merge(bars)
.transition()
.attr("x", (d, i) => xScale(i)) // update x position of bars
.attr("y", d => height - yScale(d[1]))
.attr("height", d => yScale(d[1]))
.attr("fill", d => cScale(d[1]));
let labels = graph.selectAll("text.label")
.data(data, d => d[0]);
labels.enter()
.append("text")
.attr("class", "label")
.text(d => d[1])
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(0) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.merge(labels)
.transition()
.text(d => d[1])
.attr("y", d => height - yScale(d[1]) + 15)
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2); // update x position of labels
}
return graph.node();
}
Insert cell
Insert cell
{
const width = 500;
const height = 100;
const padding = {top: 15, left: 0, right: 0, bottom: 0};
const graph = d3.select(DOM.svg(width, height));
graph.append("text")
.attr("y", padding.top)
.text("Action!")
.style("cursor", "hand")
.on("click", updateData);
let data = getIndexedRandomDataset();
const barPadding = 1;
const xScale = d3.scaleBand()
.domain(d3.range(data.length))
.rangeRound([padding.left, width - padding.right])
.paddingInner(0.05);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d[1])])
.range([padding.bottom, height - padding.top]);
const cScale = d3.scaleSequential()
.interpolator(d3.interpolateGreens)
.domain([0, d3.max(data, d => d[1])]);
graph.selectAll("rect")
.data(data, d => d[0])
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(d[1]))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(d[1]))
.attr("fill", d => cScale(d[1]));
graph.selectAll("text.label")
.data(data)
.enter()
.append("text")
.attr("class", "label")
.text(d => d[1])
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(d[1]) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
function updateData() {
data.push(...getIndexedRandomDataset(data[data.length - 1][0], 1, 40));
data.shift();
// update the scales
yScale.domain([0, d3.max(data, d => d[1])]);
cScale.domain([0, d3.max(data, d => d[1])]);
let bars = graph.selectAll("rect")
.data(data, d => d[0]);
bars.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(0))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(0))
.attr("fill", d => cScale(d[1]))
.merge(bars)
.transition()
.attr("x", (d, i) => xScale(i))
.attr("y", d => height - yScale(d[1]))
.attr("height", d => yScale(d[1]))
.attr("fill", d => cScale(d[1]));
bars.exit()
.transition()
.attr("y", d => height - yScale(0))
.attr("height", d => yScale(0))
.remove();
let labels = graph.selectAll("text.label")
.data(data, d => d[0]);
labels.enter()
.append("text")
.attr("class", "label")
.text(d => d[1])
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2)
.attr("y", d => height - yScale(0) + 15)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.merge(labels)
.transition()
.text(d => d[1])
.attr("y", d => height - yScale(d[1]) + 15)
.attr("x", (d, i) => xScale(i) + xScale.bandwidth() / 2);
// here we specify what to do with removed data: move to the left with a transition and remove
labels.exit()
.transition()
.attr("y", d => height - yScale(0) + 15)
.remove();
}
return graph.node();
}
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