Public
Edited
May 29, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
updateBarsOld = (svg, data) => {
const rectWidth = 50
// ✨ OUR CODE HERE
const rect = d3.select(svg).selectAll("rect")
.data(data, d => d)

rect.exit().remove()

const enter = rect.enter().append("rect")
.attr("width", rectWidth)
.attr("fill", "pink")
.attr("stroke", "plum")

enter.merge(rect)
.attr("x", (d, i) => i * rectWidth)
.attr("y", d => 100 - d)
.attr("height", d => d)
}
Insert cell
Insert cell
updateBarsNew = (svg, data) => {
const rectWidth = 50

// ✨ OUR CODE HERE
d3.select(svg).selectAll("rect")
.data(data, d => d)
.join("rect")
.attr("width", rectWidth)
.attr("fill", "pink")
.attr("stroke", "plum")
.attr("x", (d, i) => i * rectWidth)
.attr("y", d => 100 - d)
.attr("height", d => d)
}
Insert cell
Insert cell
{
const oldSVG = html`<svg height=100 style='overflow: visible' />`
const newSVG = html`<svg height=100 style='overflow: visible' />`
const code = html`<code />`
const button = html`<button>new data!</button>`
d3.select(button).on('click', d => {
// randomly generate an array of data
const data = _.times(_.random(3, 8), i => _.random(0, 100))

updateBarsOld(oldSVG, data)
updateBarsNew(newSVG, data)
// update div with new data array:
d3.select(code).text(JSON.stringify(data).replace(/\,/g, ', '))
})
return html`
<h4>old way:</h4>
${oldSVG}
<h4>new way:</h4>
${newSVG}
<p>
${button} ${code}
</p>
`
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const rectWidth = 50
const svgHeight = 100
const svg = html`<svg height=${svgHeight} style='overflow: visible' />`
const code = html`<code />`
const button = html`<button>new data!</button>`
function updateBars() {
// select svg so that transition can be localized within selection
const t = d3.select(svg).transition().duration(1000)
// randomly generate an array of data
const data = _.times(_.random(3, 8), i => _.random(0, 100))
// ✨ YOUR CODE HERE
d3.select(svg).selectAll("rect")
.data(data, d => d)
.join(
enter => {
const rect = enter.append("rect")
// attributes to transition FROM
.attr("fill", "pink")
.attr("fill-opacity", 0.5)
.attr("stroke", "plum")
.attr("stroke-width", 2)
.attr("x", (d, i) => i * rectWidth)
.attr("y", svgHeight)
.attr("height", 0)

return rect
},
update => update,
exit => {
exit.transition(t)
// attributes to transition TO
.attr("y", svgHeight)
.attr("height", 0)
.remove()
},
)
.attr("width", rectWidth)
// enter + update selection
.transition(t)
// attributes to transition TO
.attr('x', (d, i) => i * rectWidth)
.attr("y", d => svgHeight - d)
.attr("height", d => d)
// update div with new data array:
d3.select(code).text(JSON.stringify(data).replace(/\,/g, ', '))
}
updateBars()
d3.select(button).on('click', updateBars)
return html`
${svg}
<p>
${button} ${code}
</p>
`
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
filtered = _.filter(movies, d => {
// either the genre is in the filtered genres
return (_.includes(filteredGenres, d.genres[0]) ||
// OR the movie's genre isn't one of the top genres, and "Other" is toggled
(_.includes(filteredGenres, 'Other') && !_.includes(topGenres, d.genres[0]))) &&
// AND movie's pg rating is in filtered pg
_.includes(filteredPG, d.rated)
})
Insert cell
filteredFlowers = calculateData(filtered)
Insert cell
{
// this line is a little bit of Observable magic to make sure that every time
// our filter cells update, we use the existing SVG element instead of trashing it and creating a new one
// if you're working in your index.html, you'd create your svg element and select it as we did before
const element = this || scrollSVG(html`<svg width=${width} height=${svgHeight}></svg>`)
const svg = d3.select(element).select('svg')
// create transition animation localized to svg selection
const t = svg.transition().duration(1000)
// ✨ YOUR CODE HERE
svg.selectAll("g")
.data(filteredFlowers, d => d.title)
.join(
enter => {
const g = enter.append("g")
.attr("opacity", 0)
.attr("transform", d => `translate(${d.translate})`)

g.selectAll("path")
.data(d => _.times(d.numPetals, i => ({ ...d, rotate: i * (360 / d.numPetals) })))
.join("path")
.attr("d", d => d.path)
.attr("fill", d => d.color)
.attr("fill-opacity", 0.5)
.attr("stroke", d => d.color)
.attr("stroke-width", 2)
.transition(t)
.attr("transform", d => `rotate(${d.rotate})scale(${d.scale})`)

g.append("text")
.attr("text-anchor", "middle")
.attr("font-style", "italic")
.attr("font-size", ".7em")
.attr("dy", ".35em")
.text(d => _.truncate(d.title, { length: 20 }))

return g
},
update => update,
exit => {
exit.transition(t)
.attr("opacity", 0)
.remove()
}
).transition(t)
.attr("opacity", 1)
.attr("transform", d => `translate(${d.translate})`)
return element
}
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