Just adding some random colors from Shneiderman's Treemap art to @Kcnarf's block
This block is a recreation, inspired from [https://twitter.com/JacobJoaquin/status/816640932212772864] (https://twitter.com/JacobJoaquin/status/816640932212772864), and is more or less data art.
This block is forked from mbostock's block: Nested Treemap, and hence vizualises the treemap of the famous flare.csv.
Even if this block is a recreation, the technique can be used to distord the treemap in order to fit a particular contour/shape. I will experiment this in another block.
forked from Kcnarf's block: Wavy Treemap
forked from anonymous's block: Wavy Treemap
forked from anonymous's block: Wavy Treemap
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<title>Wavy treemap</title>
<meta content="D3's source, displayed as a wavy treemap" name="description">
<style>
path {
fill:white;
}
.node--hover path {
fill: lightgrey;
}
</style>
</head>
<body>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script>
var WITH_TRANSITION = true,
WITHOUT_TRANSITION = false;
//begin: distrosion conf.
var sampling = 5,
amplitude = 10,
dxOfY, //function defining the distorsion along the y-axis; set later
dyOfX; //function defining the distorsion along the x-axis; set later
//end: distorsion conf.
//begin: drawing conf.
var margin = {top: 5, right: 5, bottom: 5, left: 5},
svgSize = 500,
svgWidth = size,
svgHeight = size,
size = svgSize - margin.left - margin.top - 2*amplitude,
width = size,
height = size;
//end: drawing conf.
var drawingArea = d3.select("svg").append("g").attr("transform", "translate(15,15)")
var format = d3.format(",d");
var stratify = d3.stratify()
.parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")); });
var treemap = d3.treemap()
.size([width, height])
.paddingOuter(3)
.paddingInner(1)
.round(true);
d3.csv("flare.csv", function(error, data) {
if (error) throw error;
var root = stratify(data)
.sum(function(d) { return d.value; })
.sort(function(a, b) { return b.height - a.height || b.value - a.value; });
treemap(root);
var cell = drawingArea
.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; })
.attr("class", "node")
.each(function(d) { d.node = this; })
.on("mouseover", hovered(true))
.on("mouseout", hovered(false))
.style("stroke", function(d) { return d3.interpolateGreys(1-d.depth/8); });
cell.append("title")
.text(function(d) { return d.id + "\n" + format(d.value); });
cell = cell.append("path")
.attr("id", function(d) { return "path-" + d.id; })
.style("fill", function (d) {
return ["#4650a6","#dd2d28", "#edef00", "white", "white", "white"][Math.floor(Math.random()*6)];
})
//draw the default, linear, treemap
distord(cell, dxOfY_linear, dyOfX_linear, WITHOUT_TRANSITION);
dxOfY = dxOfY_wave; //set the distrosion along the y-axis
dyOfX = dyOfY_wave; //set the distorsion along the x-axis
//uncomment below code for other distorsion along the y-axis
//dxOfY = dxOfY_linear // no distorsion
dxOfY = dxOfY_circle; // cicle-based distorsion
//dxOfY = dxOfY_thirdCircle; // centered-1/3height-circle distorsion
//transition to the distorted treemap
distord(cell, dxOfY, dyOfX, WITH_TRANSITION);
});
/******************************************/
/* draw path-based cells instead of rects */
/* by interpolating lines into pathes */
/******************************************/
function distord(cellSelection, dxOfY, dyOfX, withTransition) {
var duration = withTransition? 5000 : 0;
//begin: pre-compute distorsions for optimization purpose
var dyOfXs = {}, dxOfYs = {};
//begin: store y-deltas along the x-axis
var x=0;
while (x<=width) {
dyOfXs[x] = dyOfX(x);
x+=sampling;
}
//end: store y-deltas along the x-axis
//begin: store x-deltas along the y-axis
var y = 0;
while (y<=height) {
dxOfYs[y] = dxOfY(y);
y+=sampling;
}
//end: store x-deltas along the y-axis
//end: pre-compute distorsions for optimization purpose
cellSelection.transition().duration(duration).attr("d", function(d) {
var cellWidth = (d.x1 - d.x0), cellHeight = (d.y1 - d.y0);
var absX, absY, //absolute x,y
relX, relY; //relative x,y, because the "g.cell" cell is already translated
var dyOfX0 = dyOfX(d.x0), dxOfY0 = dxOfY(d.y0),
dyOfX1 = dyOfX(d.x1), dxOfY1 = dxOfY(d.y1);
var path;
path = "M" + [0+dxOfY0,0+dyOfX0];
//begin: path of distorted top line (r->l)
absX = Math.ceil(d.x0/sampling)*sampling; //first sampling-based x
relX = absX - d.x0;
while (absX<d.x1) {
path += "L" + [relX+dxOfY0, 0+dyOfXs[absX]];
absX += sampling;
relX += sampling;
}
path += "L" + [cellWidth+dxOfY0, 0+dyOfX1];
//begin: path of distorted top line (r->l)
//begin: path of distorted right line (t->b)
absY = Math.ceil(d.y0/sampling)*sampling; //first sampling-based y
relY = absY-d.y0;
while (absY<d.y1) {
path += "L" + [cellWidth+dxOfYs[absY], relY+dyOfX1];
absY += sampling;
relY += sampling;
}
path += "L" + [cellWidth+dxOfY1, cellHeight+dyOfX1];
//begin: path of distorted right line (t->b)
//begin: path of distorted bottom line (l->r)
absX = Math.floor(d.x1/sampling)*sampling; //first sampling-based x
relX = absX - d.x0;
while (absX>d.x0) {
path += "L" + [relX+dxOfY1, cellHeight+dyOfXs[absX]];
absX -= sampling;
relX -= sampling;
}
path += "L" + [0+dxOfY1, cellHeight+dyOfX0];
//begin: path of distorted bottm line (l->r)
//begin: path of distorted left line (b->t)
absY = Math.floor(d.y1/sampling)*sampling; //first sampling-based y
relY = absY - d.y0;
while (absY>d.y0) {
path += "L" + [0+dxOfYs[absY], relY+dyOfX0];
absY -= sampling;
relY -= sampling;
}
path += "L" + [0+dxOfY0, 0+dyOfX0];
//begin: path of distorted left line (b->t)
return path+"Z";
});
}
function hovered(hover) {
return function(d) {
d3.selectAll(d.ancestors().map(function(d) { return d.node; }))
.classed("node--hover", hover);
};
};
var dxOfY_linear = function (y) {
return 0;
}
var dxOfY_wave = function (y) {
return amplitude*Math.sin(y/height*Math.PI*2*3);
};
var dxOfY_circle = function(y) {
return (Math.sqrt(Math.pow(height/2,2) - Math.pow(y-height/2,2)));
};
var dxOfY_thirdCircle = function(y) {
if (y>height/3 && y<2*height/3) {
return Math.sqrt(Math.pow(height/6,2) - Math.pow(y-height/2,2));
} else {
return 0;
}
};
var dyOfX_linear = function (y) {
return 0;
}
var dyOfY_wave = function(x) {
return amplitude*Math.sin(x/width*Math.PI*2*3+Math.PI);
};
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://d3js.org/d3-scale-chromatic.v1.min.js