Data Visualisation with a Treemap Diagram
Posted on: August 14, 2023
The final FreeCodeCamp Data Visualisation project is to create a treemap diagram, and I decided to present top 100 video game sales like this.
d3.hierarchy
The most difficult part of this project is understanding and converting the retrieved data object into hierarchical structure before generating a treemap. Detailed document is here.
JSON data can be pass into hierarchy directly:
const data = {"name": "Video Game Sales Data Top 100","children": [{"name": "2600","children": [{"name": "Pac-Man","category": "2600","value": "7.81"}]},{"name": "Wii","children": [{"name": "Wii Sports","category": "Wii","value": "82.53"},{"name": "Mario Kart Wii","category": "Wii","value": "35.52"},{"name": "Wii Sports Resort","category": "Wii","value": "32.77"}]}]}// Takes two arguments: 1st is the dataset, 2nd is a function that returns the children of each data pointconst hierarchy = d3.hierarchy(data, d => d.children);// If we don't pass a second argument, d3 defaults to use the children field of each data pointconst hierarchy = d3.hierarchy(data);
node.sum()
Before passing the hierarchy into the treemap layout, we must call node.sum()
:
const rootData = hierarchy.sum((node) => node.value);
This function is to determine how much area each node should take, the larger value the larger area. It is done by setting each node's value to the numeric value returned by this function plus the combined value of all children.
node.sort()
Up to this point, hierarchy data is ready to be used in treemap, but we could also choose to reorder the data using node.sort()
:
const rootData = rootData.sum((a, b) => b.value - a.value);
I have sorted the data because it will give a better look when data laying out on a treemap.
d3.treemap
Based on the data, d3.treemap()
can generate the dimensions we need for making reactangles as x0, x1, y0, y1 representing each corner of the rectangle. Another common method we use with a treemap is treemap.size()
to size the treemap.
// Create a treemapconst treemap = d3.treemap().size([1000, 800]);// Treemap creates dimensions accoring to each datatreemap(rootData);
Finally we can use node.leaves()
to access to the data we need for creating rectangles.
canvas.selectAll("rect").data(rootData.leaves()).enter().append("rect").attr("width", d => d.x1 - d.x0).attr("height", d => d.y1 - d.y0).attr("transform", (d) => `translate(${d.x0}, ${d.y0})`);