Public
Edited
Dec 15, 2021
5 forks
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
Insert cell
animatedTransitions = {
const svg = d3.create("svg")
.attr("width", width)
.attr("height", 300);
const data = [1, 2, 3];
const circles = svg.selectAll('circle')
.data(data)
.join((enter) => enter.append('circle')
.attr('r', 10)
.attr('cx', 100)
.attr('cy', 100) // useful default values for animation
);
circles.transition()
.duration(1000) // duration of the animation
.delay(200) // delay animation start
.attr('cx', (d, i) => d * 50)
.attr('cy', (d, i) => 40 + i *100)
.transition() // start another transition after the first one ended
.attr('r', 20);

return svg.node();
}
Insert cell
Insert cell
animatedTransitionsWithKey = {
const svg = d3.create("svg")
.attr("width", width)
.attr("height", 80);
const cscale = d3.scaleOrdinal(d3.schemeCategory10).domain(['a', 'b', 'c', 'd']);
const xscale = d3.scaleBand().domain(['a', 'b', 'c', 'd']).range([10,200]);
function update(data) {
// key argument return a unique key/id per data-item (string)
const circles = svg.selectAll('circle')
.data(data, (d) => d)
.join((enter) => enter.append('circle')
.attr('r', 10)
.attr('cx', xscale)
.style('fill', cscale)
);
// a will be bound to the first DOM element
circles.transition()
.attr('cy', (d, i) => 10 + i * 20);
}
let data = ['a', 'b', 'c'];
update(data);
// later on... 2secs
setTimeout(() => {
data = ['c', 'a', 'd'];
// the items will move to their new position,
// and the DOM element for 'b' will be removed
// and another one for 'd' created
update(data);
}, 2000);
return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
viewof activeFilters = Inputs.checkbox(["US cities"], {label: "Filter"})
Insert cell
filteredData = (activeFilters.includes("US cities")) ? data.filter((d) => d.location.country === 'US') : data
Insert cell
chart = BarChart(filteredData, {chartHeight: 350})
Insert cell
function BarChart(data, {
chartWidth = 800,
chartHeight = 600,
marginTop = 40,
marginBottom = 10,
marginLeft = 120,
marginRight = 20,
barHeight = 25
} = {}) {
const width = chartWidth - marginLeft - marginRight;
const height = chartHeight - marginTop - marginBottom;
// Creates sources <svg> element
const svg = d3.create("svg")
.attr('width', width + marginLeft + marginRight)
.attr('height', height + marginTop + marginBottom);

// Group used to enforce margin
const g = svg.append('g').attr('transform', `translate(${marginLeft},${marginTop})`);

// Scales setup
const xScale = d3.scaleLinear().range([0, width]).domain([0, d3.max(data, (d) => d.temperature)]);
const yScale = d3.scaleBand().rangeRound([0, height]).paddingInner(0.1).domain(data.map((d) => d.location.city));

// Axis setup
const xAxis = d3.axisTop().scale(xScale);
g.append('g').attr('class','x axis').call(xAxis);
const yAxis = d3.axisLeft().scale(yScale);
g.append('g').attr('class','y axis').call(yAxis);
// Render the chart with new data

// DATA JOIN use the key argument for ensurign that the same DOM element is bound to the same data-item
const rect = g.selectAll('rect').data(data, (d) => d.location.city).join(
// ENTER
// new elements
(enter) => {
const rect_enter = enter.append('rect').attr('x', 0);
rect_enter.append('title');
return rect_enter;
},
// UPDATE
// update existing elements
(update) => update,
// EXIT
// elements that aren't associated with data
(exit) => exit.remove()
);

// ENTER + UPDATE
// both old and new elements
rect
.attr('height', yScale.bandwidth())
.attr('width', (d) => xScale(d.temperature))
.attr('y', (d) => yScale(d.location.city));

rect.select('title').text((d) => d.location.city);
return svg.node();
}
Insert cell
<style>
rect {
fill: steelblue;
fill-opacity: 0.8;
}
rect:hover {
fill-opacity: 1;
}
.axis {
font-size: smaller;
}
</style>
Insert cell
data = FileAttachment("weather.json").json()
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