Click anywhere to zoom in, or click on the top bar to zoom out.
Converting Bostock's classic to d3 v4. You may find the diff helpful in understanding the d3-hierarchy api changes! Note that I didn't touch the json.
license: gpl-3.0 |
{ | |
"flare": { | |
"analytics": { | |
"cluster": { | |
"AgglomerativeCluster": 3938, | |
"CommunityStructure": 3812, | |
"HierarchicalCluster": 6714, | |
"MergeEdge": 743 | |
}, | |
"graph": { | |
"BetweennessCentrality": 3534, | |
"LinkDistance": 5731, | |
"MaxFlowMinCut": 7840, | |
"ShortestPaths": 5914, | |
"SpanningTree": 3416 | |
}, | |
"optimization": { | |
"AspectRatioBanker": 7074 | |
} | |
}, | |
"animate": { | |
"Easing": 17010, | |
"FunctionSequence": 5842, | |
"interpolate": { | |
"ArrayInterpolator": 1983, | |
"ColorInterpolator": 2047, | |
"DateInterpolator": 1375, | |
"Interpolator": 8746, | |
"MatrixInterpolator": 2202, | |
"NumberInterpolator": 1382, | |
"ObjectInterpolator": 1629, | |
"PointInterpolator": 1675, | |
"RectangleInterpolator": 2042 | |
}, | |
"ISchedulable": 1041, | |
"Parallel": 5176, | |
"Pause": 449, | |
"Scheduler": 5593, | |
"Sequence": 5534, | |
"Transition": 9201, | |
"Transitioner": 19975, | |
"TransitionEvent": 1116, | |
"Tween": 6006 | |
}, | |
"data": { | |
"converters": { | |
"Converters": 721, | |
"DelimitedTextConverter": 4294, | |
"GraphMLConverter": 9800, | |
"IDataConverter": 1314, | |
"JSONConverter": 2220 | |
}, | |
"DataField": 1759, | |
"DataSchema": 2165, | |
"DataSet": 586, | |
"DataSource": 3331, | |
"DataTable": 772, | |
"DataUtil": 3322 | |
}, | |
"display": { | |
"DirtySprite": 8833, | |
"LineSprite": 1732, | |
"RectSprite": 3623, | |
"TextSprite": 10066 | |
}, | |
"flex": { | |
"FlareVis": 4116 | |
}, | |
"physics": { | |
"DragForce": 1082, | |
"GravityForce": 1336, | |
"IForce": 319, | |
"NBodyForce": 10498, | |
"Particle": 2822, | |
"Simulation": 9983, | |
"Spring": 2213, | |
"SpringForce": 1681 | |
}, | |
"query": { | |
"AggregateExpression": 1616, | |
"And": 1027, | |
"Arithmetic": 3891, | |
"Average": 891, | |
"BinaryExpression": 2893, | |
"Comparison": 5103, | |
"CompositeExpression": 3677, | |
"Count": 781, | |
"DateUtil": 4141, | |
"Distinct": 933, | |
"Expression": 5130, | |
"ExpressionIterator": 3617, | |
"Fn": 3240, | |
"If": 2732, | |
"IsA": 2039, | |
"Literal": 1214, | |
"Match": 3748, | |
"Maximum": 843, | |
"methods": { | |
"add": 593, | |
"and": 330, | |
"average": 287, | |
"count": 277, | |
"distinct": 292, | |
"div": 595, | |
"eq": 594, | |
"fn": 460, | |
"gt": 603, | |
"gte": 625, | |
"iff": 748, | |
"isa": 461, | |
"lt": 597, | |
"lte": 619, | |
"max": 283, | |
"min": 283, | |
"mod": 591, | |
"mul": 603, | |
"neq": 599, | |
"not": 386, | |
"or": 323, | |
"orderby": 307, | |
"range": 772, | |
"select": 296, | |
"stddev": 363, | |
"sub": 600, | |
"sum": 280, | |
"update": 307, | |
"variance": 335, | |
"where": 299, | |
"xor": 354, | |
"_": 264 | |
}, | |
"Minimum": 843, | |
"Not": 1554, | |
"Or": 970, | |
"Query": 13896, | |
"Range": 1594, | |
"StringUtil": 4130, | |
"Sum": 791, | |
"Variable": 1124, | |
"Variance": 1876, | |
"Xor": 1101 | |
}, | |
"scale": { | |
"IScaleMap": 2105, | |
"LinearScale": 1316, | |
"LogScale": 3151, | |
"OrdinalScale": 3770, | |
"QuantileScale": 2435, | |
"QuantitativeScale": 4839, | |
"RootScale": 1756, | |
"Scale": 4268, | |
"ScaleType": 1821, | |
"TimeScale": 5833 | |
}, | |
"util": { | |
"Arrays": 8258, | |
"Colors": 10001, | |
"Dates": 8217, | |
"Displays": 12555, | |
"Filter": 2324, | |
"Geometry": 10993, | |
"heap": { | |
"FibonacciHeap": 9354, | |
"HeapNode": 1233 | |
}, | |
"IEvaluable": 335, | |
"IPredicate": 383, | |
"IValueProxy": 874, | |
"math": { | |
"DenseMatrix": 3165, | |
"IMatrix": 2815, | |
"SparseMatrix": 3366 | |
}, | |
"Maths": 17705, | |
"Orientation": 1486, | |
"palette": { | |
"ColorPalette": 6367, | |
"Palette": 1229, | |
"ShapePalette": 2059, | |
"SizePalette": 2291 | |
}, | |
"Property": 5559, | |
"Shapes": 19118, | |
"Sort": 6887, | |
"Stats": 6557, | |
"Strings": 22026 | |
}, | |
"vis": { | |
"axis": { | |
"Axes": 1302, | |
"Axis": 24593, | |
"AxisGridLine": 652, | |
"AxisLabel": 636, | |
"CartesianAxes": 6703 | |
}, | |
"controls": { | |
"AnchorControl": 2138, | |
"ClickControl": 3824, | |
"Control": 1353, | |
"ControlList": 4665, | |
"DragControl": 2649, | |
"ExpandControl": 2832, | |
"HoverControl": 4896, | |
"IControl": 763, | |
"PanZoomControl": 5222, | |
"SelectionControl": 7862, | |
"TooltipControl": 8435 | |
}, | |
"data": { | |
"Data": 20544, | |
"DataList": 19788, | |
"DataSprite": 10349, | |
"EdgeSprite": 3301, | |
"NodeSprite": 19382, | |
"render": { | |
"ArrowType": 698, | |
"EdgeRenderer": 5569, | |
"IRenderer": 353, | |
"ShapeRenderer": 2247 | |
}, | |
"ScaleBinding": 11275, | |
"Tree": 7147, | |
"TreeBuilder": 9930 | |
}, | |
"events": { | |
"DataEvent": 2313, | |
"SelectionEvent": 1880, | |
"TooltipEvent": 1701, | |
"VisualizationEvent": 1117 | |
}, | |
"legend": { | |
"Legend": 20859, | |
"LegendItem": 4614, | |
"LegendRange": 10530 | |
}, | |
"operator": { | |
"distortion": { | |
"BifocalDistortion": 4461, | |
"Distortion": 6314, | |
"FisheyeDistortion": 3444 | |
}, | |
"encoder": { | |
"ColorEncoder": 3179, | |
"Encoder": 4060, | |
"PropertyEncoder": 4138, | |
"ShapeEncoder": 1690, | |
"SizeEncoder": 1830 | |
}, | |
"filter": { | |
"FisheyeTreeFilter": 5219, | |
"GraphDistanceFilter": 3165, | |
"VisibilityFilter": 3509 | |
}, | |
"IOperator": 1286, | |
"label": { | |
"Labeler": 9956, | |
"RadialLabeler": 3899, | |
"StackedAreaLabeler": 3202 | |
}, | |
"layout": { | |
"AxisLayout": 6725, | |
"BundledEdgeRouter": 3727, | |
"CircleLayout": 9317, | |
"CirclePackingLayout": 12003, | |
"DendrogramLayout": 4853, | |
"ForceDirectedLayout": 8411, | |
"IcicleTreeLayout": 4864, | |
"IndentedTreeLayout": 3174, | |
"Layout": 7881, | |
"NodeLinkTreeLayout": 12870, | |
"PieLayout": 2728, | |
"RadialTreeLayout": 12348, | |
"RandomLayout": 870, | |
"StackedAreaLayout": 9121, | |
"TreeMapLayout": 9191 | |
}, | |
"Operator": 2490, | |
"OperatorList": 5248, | |
"OperatorSequence": 4190, | |
"OperatorSwitch": 2581, | |
"SortOperator": 2023 | |
}, | |
"Visualization": 16540 | |
} | |
} | |
} |
Click anywhere to zoom in, or click on the top bar to zoom out.
Converting Bostock's classic to d3 v4. You may find the diff helpful in understanding the d3-hierarchy api changes! Note that I didn't touch the json.
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
* { | |
box-sizing: border-box; | |
} | |
html, body { | |
margin: 0; | |
padding: 0; | |
overflow: hidden; | |
font-family: helvetica, sans-serif; | |
font-size: 10px; | |
} | |
svg { | |
display: inline-block; | |
} | |
rect { | |
stroke: #fff; | |
} | |
path.line { | |
stroke-width: 2; | |
fill: none; | |
} | |
path.line.highlighted { | |
stroke-width: 4; | |
} | |
.container { | |
display: inline-block; | |
position: relative; | |
} | |
.container div { | |
position: absolute; | |
padding: 1px; | |
border: 1px solid white; | |
opacity: .2; | |
color: rgba(255,255,255,0); | |
} | |
.container div.discovered { | |
opacity: 1; | |
color: black; | |
cursor: pointer; | |
} | |
.container div.discovered:hover { | |
font-weight: bold; | |
} | |
</style> | |
<body> | |
<script src="//d3js.org/d3.v4.min.js"></script> | |
<script> | |
var sectors = [ | |
{name: "Energy", parent: "Universe"}, | |
{name: "Basic Materials", parent: "Universe"}, | |
{name: "Industrials", parent: "Universe"}, | |
{name: "Cyclical Consumer Goods & Services", parent: "Universe"}, | |
{name: "Non-Cyclical Consumer Goods & Services", parent: "Universe"}, | |
{name: "Financials", parent: "Universe"}, | |
{name: "Healthcare", parent: "Universe"}, | |
{name: "Technology", parent: "Universe"}, | |
{name: "Telecommunications Services", parent: "Universe"}, | |
{name: "Utilities", parent: "Universe"} | |
] | |
var subsectors = d3.range(80).map(function(d) { | |
var parent = sectors[Math.floor(Math.random() * sectors.length)].name | |
return { | |
name: parent.substr(0,6) + "... " + d, | |
parent: parent | |
} | |
}) | |
var data = d3.range(1000).map(getRandomSeries) | |
.sort((a,b) => b.data[b.data.length-1][1] - a.data[a.data.length-1][1]) | |
.concat(sectors, subsectors, [{name: "Universe", parent: ""}]) | |
var root = d3.stratify() | |
.id(function(d) { return d.name; }) | |
.parentId(function(d) { return d.parent; }) | |
(data) | |
.sum(function(d) { | |
return d.value ? d.value : 0; | |
}) | |
.eachAfter(function(d) { | |
if(d.data.return === undefined) { | |
if(d.children) { | |
var kids = d.children.filter(d => d.data.data) | |
d.data.return = d3.mean(kids.map(d => d.data.return)); | |
d.data.data = kids[0].data.data.map((dd,i) => [ | |
dd[0], | |
d3.mean(kids.map(ddd => ddd.data.data ? ddd.data.data[i][1] : undefined)) | |
]) | |
} | |
} | |
}) | |
.sort(function(a, b) { return b.height - a.height || b.data.return - a.data.return; }) | |
var depth = 0; | |
// | |
var width = innerWidth/2, | |
height = innerHeight, | |
marginLeft = 40, | |
format = d3.format("$.2f"); | |
var x = d3.scaleLinear() | |
.range([0, height]); | |
var y = d3.scaleLinear() | |
.range([0, width]); | |
var color = d3.scaleLinear() | |
.domain([ | |
d3.min(root.children.map(d => d.data.return)), | |
0, | |
d3.max(root.children.map(d => d.data.return)) | |
]) | |
.range(["rgb(255, 44, 44)", "rgb(200,200,200)", "rgb(99, 255, 99)"]) | |
.clamp(true); | |
var x2 = d3.scaleTime() | |
.domain(d3.extent(root.children.filter(d => d.data.data)[0].data.data.map(d => d[0]))) | |
.range([marginLeft, width]) | |
var y2 = d3.scaleLinear() | |
.domain(padExtent(d3.extent(d3.merge(root.children.filter(d => d.data.data).map(d => d.data.data.map(d => d[1])))))) | |
.range([height, 0]) | |
var line = d3.line() | |
.x(d => x2(d[0])) | |
.y(d => y2(d[1])); | |
var partition = d3.partition() | |
.size([height, width]) | |
.padding(0) | |
.round(true); | |
partition(root); | |
var container = d3.select("body").append("div") | |
.classed("container", true) | |
.style("width", width + 'px') | |
.style("height", height + 'px'); | |
var svg2 = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var rect = container.selectAll("div"); | |
rect = rect | |
.data(root.descendants()) | |
.enter().append("div") | |
.style("left", function(d) { return d.y0 + 'px'; }) | |
.style("top", function(d) { return d.x0 + 'px'; }) | |
.style("width", function(d) { return d.y1 - d.y0 + 'px'; }) | |
.style("height", function(d) { return d.x1 - d.x0 + 'px'; }) | |
.style("background", function(d) { return color(d.data.return); }) | |
// .style("opacity", function(d) { return d.depth <= depth + 1 ? 1 : .2 }) | |
// .text(d => d.depth <= depth + 1 ? d.id : '') | |
.text(d => d.id) | |
.classed("discovered", d => d.depth <= depth + 1) | |
.on("mouseenter", mouseenter) | |
.on("mouseleave", mouseleave) | |
.on("click", clicked) | |
// | |
var yAxis = d3.axisLeft(y2).tickFormat(format) | |
var yAxisG = svg2.append("g") | |
.attr("class", "axis axis--y") | |
.attr("transform", "translate(" + marginLeft + ",0)") | |
.call(yAxis) | |
var path = svg2.selectAll("path.line"); | |
path = path | |
.data(root.children, d => d.id) | |
.enter().append("path") | |
.classed("line", true) | |
.attr("d", d => d.data.data ? line(d.data.data) : '') | |
.attr("stroke", function(d) { return color(d.data.return); }) | |
// | |
function mouseenter(d) { | |
svg2.selectAll("path.line") | |
.filter((dd,ii) => dd.id == d.id) | |
.classed("highlighted", true) | |
} | |
function mouseleave(d) { | |
svg2.selectAll("path.line") | |
.filter((dd,ii) => dd.id == d.id) | |
.classed("highlighted", false) | |
} | |
function clicked(d) { | |
var newData = d.children ? d.children : [d] | |
var zooming = d.depth > depth; | |
depth = d.depth; | |
x.domain([d.x0, d.x1]); | |
y.domain([d.y0, height]).range([d.depth ? 20 : 0, height]); | |
var path = svg2.selectAll("path.line") | |
.data(newData, d => d.id) | |
var pathExit = path.exit() | |
if(zooming) { | |
pathExit | |
.remove() | |
} | |
var pathEnter = path.enter() | |
.append("path") | |
.classed("line", true) | |
.attr("d", dd => line(zooming ? dd.parent.data.data : dd.data.data)) | |
.attr("stroke", function(dd) { return color(dd.data.return); }) | |
.style("opacity", zooming ? 1 : 0) | |
color.domain([ | |
Math.min(0, d3.min(newData.map(d => d.data.return))), | |
0, | |
Math.max(0, d3.max(newData.map(d => d.data.return))) | |
]) | |
x2.domain(d3.extent(newData.filter(d => d.data.data)[0].data.data.map(d => d[0]))) | |
y2.domain(padExtent(d3.extent(d3.merge(newData.filter(d => d.data.data).map(d => d.data.data.map(d => d[1])))))) | |
var t = d3.transition() | |
.duration(750) | |
yAxisG.transition(t) | |
.call(yAxis) | |
rect | |
.classed("discovered", d => d.depth <= depth + 1) | |
.transition(t) | |
.style("left", function(d) { return y(d.y0) + 'px'; }) | |
.style("top", function(d) { return x(d.x0) + 'px'; }) | |
.style("width", function(d) { return y(d.y1) - y(d.y0) + 'px'; }) | |
.style("height", function(d) { return x(d.x1) - x(d.x0) + 'px'; }) | |
.style("background", function(d) { return color(d.data.return); }) | |
// .style("opacity", function(d) { return d.depth <= depth + 1 ? 1 : .2 }) | |
if(!zooming) { | |
pathExit | |
.transition(t) | |
.attr("d", dd => line(dd.parent.data.data)) | |
.remove() | |
} | |
path.merge(pathEnter) | |
.transition(t) | |
.attr("d", dd => line(dd.data.data)) | |
.attr("stroke", function(dd) { return color(dd.data.return); }) | |
.style("opacity", 1) | |
} | |
// | |
function getRandomSeries() { | |
var ts = getRandomTimeSeries(100) | |
return { | |
name: getRandomTicker(), | |
parent: subsectors[Math.floor(Math.random() * subsectors.length)].name, | |
value: Math.round(d3.randomLogNormal(10,1)()), | |
return: ts[ts.length-1][1] - 1, | |
data: ts | |
} | |
} | |
function getRandomTicker() { | |
var length = Math.ceil(Math.random()*4); | |
var chars = 'abcdefghijklmnopqrstuvwxyz'; | |
return d3.range(length).map(() => chars[Math.floor(Math.random()*chars.length)].toUpperCase()).join(''); | |
} | |
function getRandomTimeSeries(numPoints) { | |
var data = d3.range(numPoints).map(d => [ | |
d3.interpolateDate(new Date("2000/01/01"), new Date("2016/10/01"))(d/numPoints), | |
undefined | |
]) | |
data.forEach(function(d,i,arr) { | |
if(i==0) { | |
d[1] = 1 | |
} else { | |
d[1] = arr[i-1][1] * d3.randomNormal(1, .02)() | |
} | |
}) | |
return data | |
} | |
function padExtent(extent) { | |
var d = extent[1] - extent[0] | |
return [ | |
extent[0] - d * .1, | |
extent[1] + d * .1 | |
] | |
} | |
</script> |
var sectors = [ | |
{name: "Energy"}, | |
{name: "Basic Materials"}, | |
{name: "Industrials"}, | |
{name: "Cyclical Consumer Goods & Services"}, | |
{name: "Non-Cyclical Consumer Goods & Services"}, | |
{name: "Financials"}, | |
{name: "Healthcare"}, | |
{name: "Technology"}, | |
{name: "Telecommunications Services"}, | |
{name: "Utilities"} | |
] | |
var subsectors = d3.range(40).map(function(d) { | |
var parent = sectors[Math.floor(Math.random() * sectors.length)].name | |
return { | |
name: parent.substr(0,6) + "... " + d, | |
parent: parent | |
} | |
}) | |
var data = d3.range(100).map(getRandomSeries) | |
.sort((a,b) => b.data[b.data.length-1][1] - a.data[a.data.length-1][1]) | |
.concat(sectors, subsectors) | |
// | |
function getRandomSeries() { | |
return { | |
name: getRandomTicker(), | |
parent: subsectors[Math.floor(Math.random() * subsectors.length)].name, | |
data: getRandomTimeSeries(100) | |
} | |
} | |
function getRandomTicker() { | |
var length = Math.ceil(Math.random()*4); | |
var chars = 'abcdefghijklmnopqrstuvwxyz'; | |
return d3.range(length).map(() => chars[Math.floor(Math.random()*chars.length)].toUpperCase()).join(''); | |
} | |
function getRandomTimeSeries(numPoints) { | |
var data = d3.range(numPoints).map(d => [ | |
d3.interpolateDate(new Date("2000/01/01"), new Date("2016/10/01"))(d/numPoints), | |
undefined | |
]) | |
data.forEach(function(d,i,arr) { | |
if(i==0) { | |
d[1] = d3.randomNormal(75, 30)() | |
} else { | |
d[1] = arr[i-1][1] * d3.randomNormal(1, .02)() | |
} | |
}) | |
return data | |
} |