Public
Edited
Aug 29, 2023
3 forks
Importers
7 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
colorScale = d3.scaleOrdinal( d3.schemeSet2 )
Insert cell
Insert cell
hierarchy = {
const dataCopy = JSON.parse( JSON.stringify( data ) )

return d3.hierarchy( dataCopy )
.sum(d => d.value)
.sort((a, b) => b.value - a.value)
}
Insert cell
Insert cell
treemap = d3.treemap()
// set the size of the treemap render area
.size([ width, height ])
// set the padding between every rectangle in px
.padding(2)
// set the padding at the top of each group of rectangles
// so that we can fit the country labels
.paddingTop(10)
// Set the generator to round pixel values to the nearest value
// (makes things look better)
.round(true)
Insert cell
Insert cell
root = treemap( hierarchy )
Insert cell
chart = {

const svg = d3.create('svg')
.style('font-family', 'sans-serif')
.attr('width', width)
.attr('height', height)

const g = svg.append('g')
.attr('class', 'treemap-container')
// Place the labels for our countries
g.selectAll('text.country')
// The data is the first "generation" of children
.data( root.children )
.join('text')
.attr('class', 'country')
// The rest is just placement/styling
.attr('x', d => d.x0)
.attr('y', d => d.y0)
.attr('dy', '0.6em')
.attr('dx', 3)
.style('font-size', 12)
// Remember, the data on the original node is available on node.data (d.data here)
.text(d => d.data.name)
// Now, we place the groups for all of the leaf nodes
const leaf = g.selectAll('g.leaf')
// root.leaves() returns all of the leaf nodes
.data(root.leaves())
.join('g')
.attr('class', 'leaf')
// position each group at the top left corner of the rect
.attr('transform', d => `translate(${ d.x0 },${ d.y0 })`)
.style('font-size', 10)

// A title element tells the browser to display its text value
// in a popover when the cursor is held over a rect. This is a simple
// way to add some interactivity
leaf.append('title')
.text(d => `${ d.parent.data.name }-${ d.data.name }\n${ d.value.toLocaleString() + ' GWh' }`)

// Now we append the rects. Nothing crazy here
leaf.append('rect')
.attr('fill', d => colorScale(d.parent.data.name))
.attr('opacity', 0.7)
// the width is the right edge position - the left edge position
.attr('width', d => d.x1 - d.x0)
// same for height, but bottom - top
.attr('height', d => d.y1 - d.y0)
// make corners rounded
.attr('rx', 3)
.attr('ry', 3)

// This next section checks the width and height of each rectangle
// If it's big enough, it places labels. If not, it doesn't.
leaf.each((d, i, arr) => {
// The current leaf element
const current = arr[i]
const left = d.x0,
right = d.x1,
// calculate its width from the data
width = right - left,
top = d.y0,
bottom = d.y1,
// calculate its height from the data
height = d.y1 - d.y0

// too small to show text
const tooSmall = width < 34 || height < 25
// and append the text (you saw something similar with the pie chart (day 6)
const text = d3.select( current ).append('text')
// If it's too small, don't show the text
.attr('opacity', tooSmall ? 0 : 0.9)
.selectAll('tspan')
.data(d => [ d.data.name, d.value.toLocaleString() ])
.join('tspan')
.attr('x', 3)
.attr('y', (d,i) => i ? '2.5em' : '1.15em')
.text(d => d)

})
return svg.node();

}
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