Skip to content

Instantly share code, notes, and snippets.

@rpgove
Forked from mbostock/.block
Last active December 27, 2019 00:16
Show Gist options
  • Select an option

  • Save rpgove/3e22f658c933f42fbf264e7e8ea11080 to your computer and use it in GitHub Desktop.

Select an option

Save rpgove/3e22f658c933f42fbf264e7e8ea11080 to your computer and use it in GitHub Desktop.

Revisions

  1. rpgove revised this gist May 1, 2018. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,3 @@
    A treemap recursively subdivides area into rectangles; the area of any node in the tree corresponds to its value. This example uses color to encode the order of several perfect squares (the children of each perfect square are the nonzero digits of that perfect square). Treemap design invented by [Ben Shneiderman](http://www.cs.umd.edu/~ben/). Spiral treemap algorithm by [Tu and Shen](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.529.4319).

    The spiral treemap layout has several benefits: It preserves the order of the nodes in the tree, and it maintains a good average aspect ratio (close to the [golden ratio](https://en.wikipedia.org/wiki/Golden_ratio) in this example).
  2. rpgove revised this gist Apr 18, 2018. No changes.
  3. rpgove revised this gist Apr 18, 2018. 5 changed files with 177 additions and 444 deletions.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1 @@
    A treemap recursively subdivides area into rectangles; the area of any node in the tree corresponds to its value. This example uses color to encode different packages of the Flare visualization toolkit. Treemap design invented by [Ben Shneiderman](http://www.cs.umd.edu/~ben/). Squarified algorithm by [Bruls, Huizing and van Wijk](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.36.6685). Data courtesy [Jeff Heer](http://flare.prefuse.org/).
    A treemap recursively subdivides area into rectangles; the area of any node in the tree corresponds to its value. This example uses color to encode the order of several perfect squares (the children of each perfect square are the nonzero digits of that perfect square). Treemap design invented by [Ben Shneiderman](http://www.cs.umd.edu/~ben/). Spiral treemap algorithm by [Tu and Shen](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.529.4319).
    380 changes: 0 additions & 380 deletions flare.json
    Original file line number Diff line number Diff line change
    @@ -1,380 +0,0 @@
    {
    "name": "flare",
    "children": [
    {
    "name": "analytics",
    "children": [
    {
    "name": "cluster",
    "children": [
    {"name": "AgglomerativeCluster", "size": 3938},
    {"name": "CommunityStructure", "size": 3812},
    {"name": "HierarchicalCluster", "size": 6714},
    {"name": "MergeEdge", "size": 743}
    ]
    },
    {
    "name": "graph",
    "children": [
    {"name": "BetweennessCentrality", "size": 3534},
    {"name": "LinkDistance", "size": 5731},
    {"name": "MaxFlowMinCut", "size": 7840},
    {"name": "ShortestPaths", "size": 5914},
    {"name": "SpanningTree", "size": 3416}
    ]
    },
    {
    "name": "optimization",
    "children": [
    {"name": "AspectRatioBanker", "size": 7074}
    ]
    }
    ]
    },
    {
    "name": "animate",
    "children": [
    {"name": "Easing", "size": 17010},
    {"name": "FunctionSequence", "size": 5842},
    {
    "name": "interpolate",
    "children": [
    {"name": "ArrayInterpolator", "size": 1983},
    {"name": "ColorInterpolator", "size": 2047},
    {"name": "DateInterpolator", "size": 1375},
    {"name": "Interpolator", "size": 8746},
    {"name": "MatrixInterpolator", "size": 2202},
    {"name": "NumberInterpolator", "size": 1382},
    {"name": "ObjectInterpolator", "size": 1629},
    {"name": "PointInterpolator", "size": 1675},
    {"name": "RectangleInterpolator", "size": 2042}
    ]
    },
    {"name": "ISchedulable", "size": 1041},
    {"name": "Parallel", "size": 5176},
    {"name": "Pause", "size": 449},
    {"name": "Scheduler", "size": 5593},
    {"name": "Sequence", "size": 5534},
    {"name": "Transition", "size": 9201},
    {"name": "Transitioner", "size": 19975},
    {"name": "TransitionEvent", "size": 1116},
    {"name": "Tween", "size": 6006}
    ]
    },
    {
    "name": "data",
    "children": [
    {
    "name": "converters",
    "children": [
    {"name": "Converters", "size": 721},
    {"name": "DelimitedTextConverter", "size": 4294},
    {"name": "GraphMLConverter", "size": 9800},
    {"name": "IDataConverter", "size": 1314},
    {"name": "JSONConverter", "size": 2220}
    ]
    },
    {"name": "DataField", "size": 1759},
    {"name": "DataSchema", "size": 2165},
    {"name": "DataSet", "size": 586},
    {"name": "DataSource", "size": 3331},
    {"name": "DataTable", "size": 772},
    {"name": "DataUtil", "size": 3322}
    ]
    },
    {
    "name": "display",
    "children": [
    {"name": "DirtySprite", "size": 8833},
    {"name": "LineSprite", "size": 1732},
    {"name": "RectSprite", "size": 3623},
    {"name": "TextSprite", "size": 10066}
    ]
    },
    {
    "name": "flex",
    "children": [
    {"name": "FlareVis", "size": 4116}
    ]
    },
    {
    "name": "physics",
    "children": [
    {"name": "DragForce", "size": 1082},
    {"name": "GravityForce", "size": 1336},
    {"name": "IForce", "size": 319},
    {"name": "NBodyForce", "size": 10498},
    {"name": "Particle", "size": 2822},
    {"name": "Simulation", "size": 9983},
    {"name": "Spring", "size": 2213},
    {"name": "SpringForce", "size": 1681}
    ]
    },
    {
    "name": "query",
    "children": [
    {"name": "AggregateExpression", "size": 1616},
    {"name": "And", "size": 1027},
    {"name": "Arithmetic", "size": 3891},
    {"name": "Average", "size": 891},
    {"name": "BinaryExpression", "size": 2893},
    {"name": "Comparison", "size": 5103},
    {"name": "CompositeExpression", "size": 3677},
    {"name": "Count", "size": 781},
    {"name": "DateUtil", "size": 4141},
    {"name": "Distinct", "size": 933},
    {"name": "Expression", "size": 5130},
    {"name": "ExpressionIterator", "size": 3617},
    {"name": "Fn", "size": 3240},
    {"name": "If", "size": 2732},
    {"name": "IsA", "size": 2039},
    {"name": "Literal", "size": 1214},
    {"name": "Match", "size": 3748},
    {"name": "Maximum", "size": 843},
    {
    "name": "methods",
    "children": [
    {"name": "add", "size": 593},
    {"name": "and", "size": 330},
    {"name": "average", "size": 287},
    {"name": "count", "size": 277},
    {"name": "distinct", "size": 292},
    {"name": "div", "size": 595},
    {"name": "eq", "size": 594},
    {"name": "fn", "size": 460},
    {"name": "gt", "size": 603},
    {"name": "gte", "size": 625},
    {"name": "iff", "size": 748},
    {"name": "isa", "size": 461},
    {"name": "lt", "size": 597},
    {"name": "lte", "size": 619},
    {"name": "max", "size": 283},
    {"name": "min", "size": 283},
    {"name": "mod", "size": 591},
    {"name": "mul", "size": 603},
    {"name": "neq", "size": 599},
    {"name": "not", "size": 386},
    {"name": "or", "size": 323},
    {"name": "orderby", "size": 307},
    {"name": "range", "size": 772},
    {"name": "select", "size": 296},
    {"name": "stddev", "size": 363},
    {"name": "sub", "size": 600},
    {"name": "sum", "size": 280},
    {"name": "update", "size": 307},
    {"name": "variance", "size": 335},
    {"name": "where", "size": 299},
    {"name": "xor", "size": 354},
    {"name": "_", "size": 264}
    ]
    },
    {"name": "Minimum", "size": 843},
    {"name": "Not", "size": 1554},
    {"name": "Or", "size": 970},
    {"name": "Query", "size": 13896},
    {"name": "Range", "size": 1594},
    {"name": "StringUtil", "size": 4130},
    {"name": "Sum", "size": 791},
    {"name": "Variable", "size": 1124},
    {"name": "Variance", "size": 1876},
    {"name": "Xor", "size": 1101}
    ]
    },
    {
    "name": "scale",
    "children": [
    {"name": "IScaleMap", "size": 2105},
    {"name": "LinearScale", "size": 1316},
    {"name": "LogScale", "size": 3151},
    {"name": "OrdinalScale", "size": 3770},
    {"name": "QuantileScale", "size": 2435},
    {"name": "QuantitativeScale", "size": 4839},
    {"name": "RootScale", "size": 1756},
    {"name": "Scale", "size": 4268},
    {"name": "ScaleType", "size": 1821},
    {"name": "TimeScale", "size": 5833}
    ]
    },
    {
    "name": "util",
    "children": [
    {"name": "Arrays", "size": 8258},
    {"name": "Colors", "size": 10001},
    {"name": "Dates", "size": 8217},
    {"name": "Displays", "size": 12555},
    {"name": "Filter", "size": 2324},
    {"name": "Geometry", "size": 10993},
    {
    "name": "heap",
    "children": [
    {"name": "FibonacciHeap", "size": 9354},
    {"name": "HeapNode", "size": 1233}
    ]
    },
    {"name": "IEvaluable", "size": 335},
    {"name": "IPredicate", "size": 383},
    {"name": "IValueProxy", "size": 874},
    {
    "name": "math",
    "children": [
    {"name": "DenseMatrix", "size": 3165},
    {"name": "IMatrix", "size": 2815},
    {"name": "SparseMatrix", "size": 3366}
    ]
    },
    {"name": "Maths", "size": 17705},
    {"name": "Orientation", "size": 1486},
    {
    "name": "palette",
    "children": [
    {"name": "ColorPalette", "size": 6367},
    {"name": "Palette", "size": 1229},
    {"name": "ShapePalette", "size": 2059},
    {"name": "SizePalette", "size": 2291}
    ]
    },
    {"name": "Property", "size": 5559},
    {"name": "Shapes", "size": 19118},
    {"name": "Sort", "size": 6887},
    {"name": "Stats", "size": 6557},
    {"name": "Strings", "size": 22026}
    ]
    },
    {
    "name": "vis",
    "children": [
    {
    "name": "axis",
    "children": [
    {"name": "Axes", "size": 1302},
    {"name": "Axis", "size": 24593},
    {"name": "AxisGridLine", "size": 652},
    {"name": "AxisLabel", "size": 636},
    {"name": "CartesianAxes", "size": 6703}
    ]
    },
    {
    "name": "controls",
    "children": [
    {"name": "AnchorControl", "size": 2138},
    {"name": "ClickControl", "size": 3824},
    {"name": "Control", "size": 1353},
    {"name": "ControlList", "size": 4665},
    {"name": "DragControl", "size": 2649},
    {"name": "ExpandControl", "size": 2832},
    {"name": "HoverControl", "size": 4896},
    {"name": "IControl", "size": 763},
    {"name": "PanZoomControl", "size": 5222},
    {"name": "SelectionControl", "size": 7862},
    {"name": "TooltipControl", "size": 8435}
    ]
    },
    {
    "name": "data",
    "children": [
    {"name": "Data", "size": 20544},
    {"name": "DataList", "size": 19788},
    {"name": "DataSprite", "size": 10349},
    {"name": "EdgeSprite", "size": 3301},
    {"name": "NodeSprite", "size": 19382},
    {
    "name": "render",
    "children": [
    {"name": "ArrowType", "size": 698},
    {"name": "EdgeRenderer", "size": 5569},
    {"name": "IRenderer", "size": 353},
    {"name": "ShapeRenderer", "size": 2247}
    ]
    },
    {"name": "ScaleBinding", "size": 11275},
    {"name": "Tree", "size": 7147},
    {"name": "TreeBuilder", "size": 9930}
    ]
    },
    {
    "name": "events",
    "children": [
    {"name": "DataEvent", "size": 2313},
    {"name": "SelectionEvent", "size": 1880},
    {"name": "TooltipEvent", "size": 1701},
    {"name": "VisualizationEvent", "size": 1117}
    ]
    },
    {
    "name": "legend",
    "children": [
    {"name": "Legend", "size": 20859},
    {"name": "LegendItem", "size": 4614},
    {"name": "LegendRange", "size": 10530}
    ]
    },
    {
    "name": "operator",
    "children": [
    {
    "name": "distortion",
    "children": [
    {"name": "BifocalDistortion", "size": 4461},
    {"name": "Distortion", "size": 6314},
    {"name": "FisheyeDistortion", "size": 3444}
    ]
    },
    {
    "name": "encoder",
    "children": [
    {"name": "ColorEncoder", "size": 3179},
    {"name": "Encoder", "size": 4060},
    {"name": "PropertyEncoder", "size": 4138},
    {"name": "ShapeEncoder", "size": 1690},
    {"name": "SizeEncoder", "size": 1830}
    ]
    },
    {
    "name": "filter",
    "children": [
    {"name": "FisheyeTreeFilter", "size": 5219},
    {"name": "GraphDistanceFilter", "size": 3165},
    {"name": "VisibilityFilter", "size": 3509}
    ]
    },
    {"name": "IOperator", "size": 1286},
    {
    "name": "label",
    "children": [
    {"name": "Labeler", "size": 9956},
    {"name": "RadialLabeler", "size": 3899},
    {"name": "StackedAreaLabeler", "size": 3202}
    ]
    },
    {
    "name": "layout",
    "children": [
    {"name": "AxisLayout", "size": 6725},
    {"name": "BundledEdgeRouter", "size": 3727},
    {"name": "CircleLayout", "size": 9317},
    {"name": "CirclePackingLayout", "size": 12003},
    {"name": "DendrogramLayout", "size": 4853},
    {"name": "ForceDirectedLayout", "size": 8411},
    {"name": "IcicleTreeLayout", "size": 4864},
    {"name": "IndentedTreeLayout", "size": 3174},
    {"name": "Layout", "size": 7881},
    {"name": "NodeLinkTreeLayout", "size": 12870},
    {"name": "PieLayout", "size": 2728},
    {"name": "RadialTreeLayout", "size": 12348},
    {"name": "RandomLayout", "size": 870},
    {"name": "StackedAreaLayout", "size": 9121},
    {"name": "TreeMapLayout", "size": 9191}
    ]
    },
    {"name": "Operator", "size": 2490},
    {"name": "OperatorList", "size": 5248},
    {"name": "OperatorSequence", "size": 4190},
    {"name": "OperatorSwitch", "size": 2581},
    {"name": "SortOperator", "size": 2023}
    ]
    },
    {"name": "Visualization", "size": 16540}
    ]
    }
    ]
    }
    239 changes: 176 additions & 63 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -7,99 +7,212 @@

    svg {
    font: 10px sans-serif;
    float: left;
    }

    rect {
    stroke: #000;
    stroke-width: 1px;
    }

    </style>
    <svg width="960" height="570"></svg>
    <svg width="600" height="600"></svg>
    <form>
    <label><input type="radio" name="mode" value="sumBySize" checked> Size</label>
    <label><input type="radio" name="mode" value="sumByCount"> Count</label>
    <label><input type="radio" name="mode" value="sortAscending" checked> Ascending</label>
    <label><input type="radio" name="mode" value="sortDescending"> Descending</label>
    </form>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <script>

    var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height");

    var fader = function(color) { return d3.interpolateRgb(color, "#fff")(0.2); },
    color = d3.scaleOrdinal(d3.schemeCategory20.map(fader)),
    format = d3.format(",d");
    var minVal = 10;
    var maxVal = 40;

    var color = d3.scaleSequential()
    .domain([0, maxVal - minVal])
    .interpolator(d3.interpolateRdPu);

    var treemap = d3.treemap()
    .tile(d3.treemapResquarify)
    .size([width, height])
    .round(true)
    .paddingInner(1);

    d3.json("flare.json", function(error, data) {
    if (error) throw error;

    var root = d3.hierarchy(data)
    .eachBefore(function(d) { d.data.id = (d.parent ? d.parent.data.id + "." : "") + d.data.name; })
    .sum(sumBySize)
    .sort(function(a, b) { return b.height - a.height || b.value - a.value; });

    treemap(root);

    var cell = svg.selectAll("g")
    .data(root.leaves())
    .enter().append("g")
    .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; });

    cell.append("rect")
    .attr("id", function(d) { return d.data.id; })
    .attr("width", function(d) { return d.x1 - d.x0; })
    .attr("height", function(d) { return d.y1 - d.y0; })
    .attr("fill", function(d) { return color(d.parent.data.id); });

    cell.append("clipPath")
    .attr("id", function(d) { return "clip-" + d.data.id; })
    .append("use")
    .attr("xlink:href", function(d) { return "#" + d.data.id; });

    cell.append("text")
    .paddingOuter(1)
    .tile(treemapSpiral);

    var data = generateData();

    var root = d3.hierarchy(data)
    .eachBefore(function(d) {
    d.data.id = (d.parent ? d.parent.data.id + "." : "") + d.data.name + '-' + d.data.index;
    })
    .sum(function (d) { return d.size; })
    .sort(sortAscending);

    treemap(root);

    var cell = svg.selectAll("g")
    .data(root.leaves())
    .enter().append("g")
    .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; });

    cell.append("rect")
    .attr("id", function(d) { return d.data.id; })
    .attr("width", function(d) { return d.x1 - d.x0; })
    .attr("height", function(d) { return d.y1 - d.y0; })
    .attr("stroke", function(d) { return d3.color(color(d.parent.data.index || d.data.index)).darker(1); })
    .attr("fill", function(d) { return color(d.parent.data.index || d.data.index); });

    cell.append("clipPath")
    .attr("id", function(d) { return "clip-" + d.data.id; })
    .append("use")
    .attr("xlink:href", function(d) { return "#" + d.data.id; });

    cell.append("text")
    .attr("clip-path", function(d) { return "url(#clip-" + d.data.id + ")"; })
    .selectAll("tspan")
    .data(function(d) { return d.data.name.split(/(?=[A-Z][^A-Z])/g); })
    .data(function(d) { return d.data.name.split('.'); })
    .enter().append("tspan")
    .attr("x", 4)
    .attr("y", function(d, i) { return 13 + i * 10; })
    .text(function(d) { return d; });

    cell.append("title")
    .text(function(d) { return d.data.id + "\n" + format(d.value); });
    cell.append("title")
    .text(function(d) { return d.parent.data.size + ' -> ' + d.value; });

    d3.selectAll("input")
    .data([sumBySize, sumByCount], function(d) { return d ? d.name : this.value; })
    .on("change", changed);
    d3.selectAll("input")
    .data([sortAscending, sortDescending], function(d) { return d ? d.name : this.value; })
    .on("change", changed);

    var timeout = d3.timeout(function() {
    d3.select("input[value=\"sumByCount\"]")
    .property("checked", true)
    .dispatch("change");
    }, 2000);
    function changed(sort) {
    treemap(root.sort(sort));

    function changed(sum) {
    timeout.stop();
    cell.transition()
    .duration(750)
    .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; })
    .select("rect")
    .attr("width", function(d) { return d.x1 - d.x0; })
    .attr("height", function(d) { return d.y1 - d.y0; });
    }

    treemap(root.sum(sum));
    function sortDescending (a, b) { return b.height - a.height || b.value - a.value; }

    cell.transition()
    .duration(750)
    .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; })
    .select("rect")
    .attr("width", function(d) { return d.x1 - d.x0; })
    .attr("height", function(d) { return d.y1 - d.y0; });
    }
    });
    function sortAscending (a, b) { return a.height - b.height || a.value - b.value; }

    function sumByCount(d) {
    return d.children ? 0 : 1;
    function generateData() {
    var firstLevel = d3.range(minVal, maxVal).map(function (d, i) {
    return {name: Number(d * d).toString(), size: d * d, index: i};
    });

    var result = {
    name: 'squared',
    index: 0,
    children: firstLevel
    };

    result.children.forEach(function (d) {
    d.children = Number(d.size).toString().split('').filter(function (s) { return +s; }).map(function (s, i) {
    return {name: d.name + '.' + s, size: +s, index: i};
    });
    });

    return result;
    }

    function sumBySize(d) {
    return d.size;
    function treemapSpiral (parent, x0, y0, x1, y1) {
    var EAST = 0;
    var SOUTH = 1;
    var WEST = 2;
    var NORTH = 3;
    var direction = EAST;
    var nodes = parent.children;
    var node;
    var n = nodes.length;
    var i = -1;
    var newX0 = x0;
    var newX1 = x1;
    var newY0 = y0;
    var newY1 = y1;
    var availWidth = x1 - x0;
    var availHeight = y1 - y0;
    var avgAspectRatio = 0;
    var nodeAspectRatio = 0;
    var segment = [];
    var segmentSum = 0;
    var nodesSum = 0;

    for (i = n; i--;) nodesSum += nodes[i].value;

    i = -1;

    while (++i < n) {
    node = nodes[i];

    segment.push(node);

    segmentSum += node.value;

    if (direction === EAST) {
    // Update positions for each node.
    segment.forEach(function (d, i, arr) {
    d.x0 = i ? arr[i-1].x1 : newX0;
    d.x1 = d.x0 + (d.value / segmentSum) * availWidth;
    d.y0 = newY0;
    d.y1 = newY0 + (segmentSum / nodesSum) * availHeight;
    });
    } else if (direction === SOUTH) {
    segment.forEach(function (d, i, arr) {
    d.x0 = newX1 - (segmentSum / nodesSum) * availWidth;
    d.x1 = newX1;
    d.y0 = i ? arr[i-1].y1 : newY0;
    d.y1 = d.y0 + (d.value / segmentSum) * availHeight;
    });
    } else if (direction === WEST) {
    segment.forEach(function (d, i, arr) {
    d.x1 = i ? arr[i-1].x0 : newX1;
    d.x0 = d.x1 - (d.value / segmentSum) * availWidth;
    d.y0 = newY1 - (segmentSum / nodesSum) * availHeight;
    d.y1 = newY1;
    });
    } else if (direction === NORTH) {
    segment.forEach(function (d, i, arr) {
    d.x1 = newX0 + (segmentSum / nodesSum) * availWidth;
    d.x0 = newX0;
    d.y1 = i ? arr[i-1].y0 : newY1;
    d.y0 = d.y1 - (d.value / segmentSum) * availHeight;
    });
    }

    // Compute new aspect ratio.
    nodeAspectRatio = direction & 1 ? (node.y1 - node.y0) / (node.x1 - node.x0) : (node.x1 - node.x0) / (node.y1 - node.y0);
    avgAspectRatio = d3.sum(segment, function (d) {
    return direction & 1 ? (d.y1 - d.y0) / (d.x1 - d.x0) : (d.x1 - d.x0) / (d.y1 - d.y0);
    });

    // If avg aspect ratio is small, update boundaries and start a new segment.
    if (avgAspectRatio / segment.length < 1.618033988749895) {
    if (direction === EAST) {
    newY0 = node.y1;
    availHeight = newY1 - newY0;
    } else if (direction === SOUTH) {
    newX1 = node.x0;
    availWidth = newX1 - newX0;
    } else if (direction === WEST) {
    newY1 = node.y0;
    availHeight = newY1 - newY0;
    } else if (direction === NORTH) {
    newX0 = node.x1;
    availWidth = newX1 - newX0;
    }

    nodesSum -= segmentSum;
    segment.length = 0;
    segmentSum = 0;
    avgAspectRatio = 0;
    direction = (direction + 1) % 4;
    }
    }
    }

    </script>
    Binary file added preview.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file modified thumbnail.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  4. @mbostock mbostock revised this gist Dec 7, 2016. 1 changed file with 10 additions and 2 deletions.
    12 changes: 10 additions & 2 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -72,9 +72,17 @@

    d3.selectAll("input")
    .data([sumBySize, sumByCount], function(d) { return d ? d.name : this.value; })
    .on("change", update);
    .on("change", changed);

    var timeout = d3.timeout(function() {
    d3.select("input[value=\"sumByCount\"]")
    .property("checked", true)
    .dispatch("change");
    }, 2000);

    function changed(sum) {
    timeout.stop();

    function update(sum) {
    treemap(root.sum(sum));

    cell.transition()
  5. @mbostock mbostock revised this gist Dec 7, 2016. 1 changed file with 12 additions and 4 deletions.
    16 changes: 12 additions & 4 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -29,6 +29,7 @@
    var treemap = d3.treemap()
    .tile(d3.treemapResquarify)
    .size([width, height])
    .round(true)
    .paddingInner(1);

    d3.json("flare.json", function(error, data) {
    @@ -39,18 +40,26 @@
    .sum(sumBySize)
    .sort(function(a, b) { return b.height - a.height || b.value - a.value; });

    treemap(root);

    var cell = svg.selectAll("g")
    .data(treemap(root).leaves())
    .data(root.leaves())
    .enter().append("g")
    .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; });

    cell.append("rect")
    .attr("id", function(d) { return "rect-" + d.data.id; })
    .attr("id", function(d) { return d.data.id; })
    .attr("width", function(d) { return d.x1 - d.x0; })
    .attr("height", function(d) { return d.y1 - d.y0; })
    .attr("fill", function(d) { return color(d.parent.data.id); });

    cell.append("clipPath")
    .attr("id", function(d) { return "clip-" + d.data.id; })
    .append("use")
    .attr("xlink:href", function(d) { return "#" + d.data.id; });

    cell.append("text")
    .attr("clip-path", function(d) { return "url(#clip-" + d.data.id + ")"; })
    .selectAll("tspan")
    .data(function(d) { return d.data.name.split(/(?=[A-Z][^A-Z])/g); })
    .enter().append("tspan")
    @@ -66,8 +75,7 @@
    .on("change", update);

    function update(sum) {
    cell = cell
    .data(treemap(root.sum(sum)).leaves(), function(d) { return d.data.id; });
    treemap(root.sum(sum));

    cell.transition()
    .duration(750)
  6. @mbostock mbostock revised this gist Dec 7, 2016. 1 changed file with 3 additions and 9 deletions.
    12 changes: 3 additions & 9 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -1,26 +1,20 @@
    <!DOCTYPE html>
    <style>

    body {
    font-family: sans-serif;
    }

    form {
    width: 960px;
    text-align: right;
    margin-bottom: 4px;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    }

    svg {
    font-size: 10px;
    font: 10px sans-serif;
    }

    </style>
    <svg width="960" height="570"></svg>
    <form>
    <label><input type="radio" name="mode" value="sumBySize" checked> Size</label>
    <label><input type="radio" name="mode" value="sumByCount"> Count</label>
    </form>
    <svg width="960" height="580"></svg>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script>

  7. @mbostock mbostock revised this gist Dec 5, 2016. 2 changed files with 70 additions and 57 deletions.
    2 changes: 2 additions & 0 deletions .block
    Original file line number Diff line number Diff line change
    @@ -1 +1,3 @@
    border: no
    height: 600
    license: gpl-3.0
    125 changes: 68 additions & 57 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -1,84 +1,95 @@
    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>

    body {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    margin: auto;
    position: relative;
    width: 960px;
    font-family: sans-serif;
    }

    form {
    position: absolute;
    right: 10px;
    top: 10px;
    width: 960px;
    text-align: right;
    margin-bottom: 4px;
    }

    .node {
    border: solid 1px white;
    font: 10px sans-serif;
    line-height: 12px;
    overflow: hidden;
    position: absolute;
    text-indent: 2px;
    svg {
    font-size: 10px;
    }

    </style>
    <form>
    <label><input type="radio" name="mode" value="size" checked> Size</label>
    <label><input type="radio" name="mode" value="count"> Count</label>
    <label><input type="radio" name="mode" value="sumBySize" checked> Size</label>
    <label><input type="radio" name="mode" value="sumByCount"> Count</label>
    </form>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <svg width="960" height="580"></svg>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script>

    var margin = {top: 40, right: 10, bottom: 10, left: 10},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
    var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height");

    var color = d3.scale.category20c();
    var fader = function(color) { return d3.interpolateRgb(color, "#fff")(0.2); },
    color = d3.scaleOrdinal(d3.schemeCategory20.map(fader)),
    format = d3.format(",d");

    var treemap = d3.layout.treemap()
    var treemap = d3.treemap()
    .tile(d3.treemapResquarify)
    .size([width, height])
    .sticky(true)
    .value(function(d) { return d.size; });

    var div = d3.select("body").append("div")
    .style("position", "relative")
    .style("width", (width + margin.left + margin.right) + "px")
    .style("height", (height + margin.top + margin.bottom) + "px")
    .style("left", margin.left + "px")
    .style("top", margin.top + "px");
    .paddingInner(1);

    d3.json("flare.json", function(error, root) {
    d3.json("flare.json", function(error, data) {
    if (error) throw error;

    var node = div.datum(root).selectAll(".node")
    .data(treemap.nodes)
    .enter().append("div")
    .attr("class", "node")
    .call(position)
    .style("background", function(d) { return d.children ? color(d.name) : null; })
    .text(function(d) { return d.children ? null : d.name; });

    d3.selectAll("input").on("change", function change() {
    var value = this.value === "count"
    ? function() { return 1; }
    : function(d) { return d.size; };

    node
    .data(treemap.value(value).nodes)
    .transition()
    .duration(1500)
    .call(position);
    });
    var root = d3.hierarchy(data)
    .eachBefore(function(d) { d.data.id = (d.parent ? d.parent.data.id + "." : "") + d.data.name; })
    .sum(sumBySize)
    .sort(function(a, b) { return b.height - a.height || b.value - a.value; });

    var cell = svg.selectAll("g")
    .data(treemap(root).leaves())
    .enter().append("g")
    .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; });

    cell.append("rect")
    .attr("id", function(d) { return "rect-" + d.data.id; })
    .attr("width", function(d) { return d.x1 - d.x0; })
    .attr("height", function(d) { return d.y1 - d.y0; })
    .attr("fill", function(d) { return color(d.parent.data.id); });

    cell.append("text")
    .selectAll("tspan")
    .data(function(d) { return d.data.name.split(/(?=[A-Z][^A-Z])/g); })
    .enter().append("tspan")
    .attr("x", 4)
    .attr("y", function(d, i) { return 13 + i * 10; })
    .text(function(d) { return d; });

    cell.append("title")
    .text(function(d) { return d.data.id + "\n" + format(d.value); });

    d3.selectAll("input")
    .data([sumBySize, sumByCount], function(d) { return d ? d.name : this.value; })
    .on("change", update);

    function update(sum) {
    cell = cell
    .data(treemap(root.sum(sum)).leaves(), function(d) { return d.data.id; });

    cell.transition()
    .duration(750)
    .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; })
    .select("rect")
    .attr("width", function(d) { return d.x1 - d.x0; })
    .attr("height", function(d) { return d.y1 - d.y0; });
    }
    });

    function position() {
    this.style("left", function(d) { return d.x + "px"; })
    .style("top", function(d) { return d.y + "px"; })
    .style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
    .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
    function sumByCount(d) {
    return d.children ? 0 : 1;
    }

    function sumBySize(d) {
    return d.size;
    }

    </script>
  8. @mbostock mbostock revised this gist Feb 9, 2016. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions .block
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    license: gpl-3.0
  9. @mbostock mbostock revised this gist Oct 31, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -29,7 +29,7 @@
    <label><input type="radio" name="mode" value="size" checked> Size</label>
    <label><input type="radio" name="mode" value="count"> Count</label>
    </form>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script>

    var margin = {top: 40, right: 10, bottom: 10, left: 10},
  10. @mbostock mbostock revised this gist Jun 11, 2015. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -29,7 +29,7 @@
    <label><input type="radio" name="mode" value="size" checked> Size</label>
    <label><input type="radio" name="mode" value="count"> Count</label>
    </form>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <script>

    var margin = {top: 40, right: 10, bottom: 10, left: 10},
    @@ -51,6 +51,8 @@
    .style("top", margin.top + "px");

    d3.json("flare.json", function(error, root) {
    if (error) throw error;

    var node = div.datum(root).selectAll(".node")
    .data(treemap.nodes)
    .enter().append("div")
    @@ -79,4 +81,4 @@
    .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
    }

    </script>
    </script>
  11. @mbostock mbostock revised this gist Nov 13, 2012. 1 changed file with 0 additions and 0 deletions.
    Binary file added thumbnail.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  12. @mbostock mbostock revised this gist Nov 13, 2012. 1 changed file with 6 additions and 5 deletions.
    11 changes: 6 additions & 5 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -32,10 +32,11 @@
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>

    var margin = {top: 30, right: 10, bottom: 10, left: 10},
    var margin = {top: 40, right: 10, bottom: 10, left: 10},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom,
    color = d3.scale.category20c();
    height = 500 - margin.top - margin.bottom;

    var color = d3.scale.category20c();

    var treemap = d3.layout.treemap()
    .size([width, height])
    @@ -46,8 +47,8 @@
    .style("position", "relative")
    .style("width", (width + margin.left + margin.right) + "px")
    .style("height", (height + margin.top + margin.bottom) + "px")
    .style("margin-left", margin.left + "px")
    .style("margin-top", margin.top + "px");
    .style("left", margin.left + "px")
    .style("top", margin.top + "px");

    d3.json("flare.json", function(error, root) {
    var node = div.datum(root).selectAll(".node")
  13. @mbostock mbostock revised this gist Nov 13, 2012. 1 changed file with 8 additions and 5 deletions.
    13 changes: 8 additions & 5 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -32,8 +32,9 @@
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>

    var width = 960,
    height = 500,
    var margin = {top: 30, right: 10, bottom: 10, left: 10},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom,
    color = d3.scale.category20c();

    var treemap = d3.layout.treemap()
    @@ -43,8 +44,10 @@

    var div = d3.select("body").append("div")
    .style("position", "relative")
    .style("width", width + "px")
    .style("height", height + "px");
    .style("width", (width + margin.left + margin.right) + "px")
    .style("height", (height + margin.top + margin.bottom) + "px")
    .style("margin-left", margin.left + "px")
    .style("margin-top", margin.top + "px");

    d3.json("flare.json", function(error, root) {
    var node = div.datum(root).selectAll(".node")
    @@ -75,4 +78,4 @@
    .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
    }

    </script>
    </script>
  14. @mbostock mbostock revised this gist Nov 13, 2012. 2 changed files with 54 additions and 45 deletions.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1 @@
    A dendrogram is a node-link diagram that places leaf nodes of the tree at the same depth. In this example, the classes (leaf nodes) are aligned on the right edge, with the packages (internal nodes) to the left. Data shows the [Flare](http://flare.prefuse.org/) class hierarchy, courtesy Jeff Heer.
    A treemap recursively subdivides area into rectangles; the area of any node in the tree corresponds to its value. This example uses color to encode different packages of the Flare visualization toolkit. Treemap design invented by [Ben Shneiderman](http://www.cs.umd.edu/~ben/). Squarified algorithm by [Bruls, Huizing and van Wijk](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.36.6685). Data courtesy [Jeff Heer](http://flare.prefuse.org/).
    97 changes: 53 additions & 44 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -2,68 +2,77 @@
    <meta charset="utf-8">
    <style>

    .node circle {
    fill: #fff;
    stroke: steelblue;
    stroke-width: 1.5px;
    body {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    margin: auto;
    position: relative;
    width: 960px;
    }

    .node {
    font: 10px sans-serif;
    form {
    position: absolute;
    right: 10px;
    top: 10px;
    }

    .link {
    fill: none;
    stroke: #ccc;
    stroke-width: 1.5px;
    .node {
    border: solid 1px white;
    font: 10px sans-serif;
    line-height: 12px;
    overflow: hidden;
    position: absolute;
    text-indent: 2px;
    }

    </style>
    <body>
    <form>
    <label><input type="radio" name="mode" value="size" checked> Size</label>
    <label><input type="radio" name="mode" value="count"> Count</label>
    </form>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>

    var width = 960,
    height = 2200;
    height = 500,
    color = d3.scale.category20c();

    var cluster = d3.layout.cluster()
    .size([height, width - 160]);
    var treemap = d3.layout.treemap()
    .size([width, height])
    .sticky(true)
    .value(function(d) { return d.size; });

    var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

    var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(40,0)");
    var div = d3.select("body").append("div")
    .style("position", "relative")
    .style("width", width + "px")
    .style("height", height + "px");

    d3.json("flare.json", function(error, root) {
    var nodes = cluster.nodes(root),
    links = cluster.links(nodes);

    var link = svg.selectAll(".link")
    .data(links)
    .enter().append("path")
    .attr("class", "link")
    .attr("d", diagonal);

    var node = svg.selectAll(".node")
    .data(nodes)
    .enter().append("g")
    var node = div.datum(root).selectAll(".node")
    .data(treemap.nodes)
    .enter().append("div")
    .attr("class", "node")
    .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
    .call(position)
    .style("background", function(d) { return d.children ? color(d.name) : null; })
    .text(function(d) { return d.children ? null : d.name; });

    node.append("circle")
    .attr("r", 4.5);
    d3.selectAll("input").on("change", function change() {
    var value = this.value === "count"
    ? function() { return 1; }
    : function(d) { return d.size; };

    node.append("text")
    .attr("dx", function(d) { return d.children ? -8 : 8; })
    .attr("dy", 3)
    .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
    .text(function(d) { return d.name; });
    node
    .data(treemap.value(value).nodes)
    .transition()
    .duration(1500)
    .call(position);
    });
    });

    d3.select(self.frameElement).style("height", height + "px");
    function position() {
    this.style("left", function(d) { return d.x + "px"; })
    .style("top", function(d) { return d.y + "px"; })
    .style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
    .style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
    }

    </script>
    </script>
  15. @mbostock mbostock revised this gist Nov 13, 2012. 2 changed files with 17 additions and 17 deletions.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1 @@
    The `tree` layout implements the Reingold-Tilford algorithm for efficient, tidy arrangement of layered nodes. The depth of nodes is computed by distance from the root, leading to a ragged appearance. Cartesian orientations are also supported. Implementation based on work by [Jeff Heer](http://jheer.org/) and [Jason Davies](http://www.jasondavies.com/) using [Buchheim et al.](http://www.springerlink.com/content/u73fyc4tlxp3uwt8/)'s linear-time variant of the Reingold-Tilford algorithm. Data shows the [Flare](http://flare.prefuse.org/) class hierarchy, also courtesy Jeff Heer.
    A dendrogram is a node-link diagram that places leaf nodes of the tree at the same depth. In this example, the classes (leaf nodes) are aligned on the right edge, with the packages (internal nodes) to the left. Data shows the [Flare](http://flare.prefuse.org/) class hierarchy, courtesy Jeff Heer.
    32 changes: 16 additions & 16 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -23,24 +23,24 @@
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>

    var diameter = 960;
    var width = 960,
    height = 2200;

    var tree = d3.layout.tree()
    .size([360, diameter / 2 - 120])
    .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
    var cluster = d3.layout.cluster()
    .size([height, width - 160]);

    var diagonal = d3.svg.diagonal.radial()
    .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
    var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

    var svg = d3.select("body").append("svg")
    .attr("width", diameter)
    .attr("height", diameter - 150)
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
    .attr("transform", "translate(40,0)");

    d3.json("flare.json", function(error, root) {
    var nodes = tree.nodes(root),
    links = tree.links(nodes);
    var nodes = cluster.nodes(root),
    links = cluster.links(nodes);

    var link = svg.selectAll(".link")
    .data(links)
    @@ -52,18 +52,18 @@
    .data(nodes)
    .enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
    .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

    node.append("circle")
    .attr("r", 4.5);

    node.append("text")
    .attr("dy", ".31em")
    .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
    .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
    .attr("dx", function(d) { return d.children ? -8 : 8; })
    .attr("dy", 3)
    .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
    .text(function(d) { return d.name; });
    });

    d3.select(self.frameElement).style("height", diameter - 150 + "px");
    d3.select(self.frameElement).style("height", height + "px");

    </script>
  16. @mbostock mbostock revised this gist Nov 13, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -64,6 +64,6 @@
    .text(function(d) { return d.name; });
    });

    d3.select(self.frameElement).style("height", diameter + "px");
    d3.select(self.frameElement).style("height", diameter - 150 + "px");

    </script>
  17. @mbostock mbostock revised this gist Nov 13, 2012. 1 changed file with 14 additions and 0 deletions.
    14 changes: 14 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,21 @@
    <meta charset="utf-8">
    <style>

    .node circle {
    fill: #fff;
    stroke: steelblue;
    stroke-width: 1.5px;
    }

    .node {
    font: 10px sans-serif;
    }

    .link {
    fill: none;
    stroke: #ccc;
    stroke-width: 1.5px;
    }

    </style>
    <body>
  18. @mbostock mbostock revised this gist Nov 13, 2012. 2 changed files with 30 additions and 35 deletions.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1 @@
    Enclosure diagrams use containment to represent the hierarchy. Although circle packing is not as space-efficient as a treemap, it better reveals the hierarchy. Implementation based on work by [Jeff Heer](http://jheer.org/). Data shows the [Flare](http://flare.prefuse.org/) class hierarchy, also courtesy Jeff Heer.
    The `tree` layout implements the Reingold-Tilford algorithm for efficient, tidy arrangement of layered nodes. The depth of nodes is computed by distance from the root, leading to a ragged appearance. Cartesian orientations are also supported. Implementation based on work by [Jeff Heer](http://jheer.org/) and [Jason Davies](http://www.jasondavies.com/) using [Buchheim et al.](http://www.springerlink.com/content/u73fyc4tlxp3uwt8/)'s linear-time variant of the Reingold-Tilford algorithm. Data shows the [Flare](http://flare.prefuse.org/) class hierarchy, also courtesy Jeff Heer.
    63 changes: 29 additions & 34 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -2,57 +2,52 @@
    <meta charset="utf-8">
    <style>

    circle {
    fill: rgb(31, 119, 180);
    fill-opacity: .25;
    stroke: rgb(31, 119, 180);
    stroke-width: 1px;
    }

    .leaf circle {
    fill: #ff7f0e;
    fill-opacity: 1;
    }

    text {
    font: 10px sans-serif;
    }


    </style>
    <body>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>

    var diameter = 960,
    format = d3.format(",d");
    var diameter = 960;

    var tree = d3.layout.tree()
    .size([360, diameter / 2 - 120])
    .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });

    var pack = d3.layout.pack()
    .size([diameter - 4, diameter - 4])
    .value(function(d) { return d.size; });
    var diagonal = d3.svg.diagonal.radial()
    .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });

    var svg = d3.select("body").append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
    .attr("height", diameter - 150)
    .append("g")
    .attr("transform", "translate(2,2)");
    .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");

    d3.json("flare.json", function(error, root) {
    var node = svg.datum(root).selectAll(".node")
    .data(pack.nodes)
    .enter().append("g")
    .attr("class", function(d) { return d.children ? "node" : "leaf node"; })
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
    var nodes = tree.nodes(root),
    links = tree.links(nodes);

    node.append("title")
    .text(function(d) { return d.name + (d.children ? "" : ": " + format(d.size)); });
    var link = svg.selectAll(".link")
    .data(links)
    .enter().append("path")
    .attr("class", "link")
    .attr("d", diagonal);

    var node = svg.selectAll(".node")
    .data(nodes)
    .enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })

    node.append("circle")
    .attr("r", function(d) { return d.r; });
    .attr("r", 4.5);

    node.filter(function(d) { return !d.children; }).append("text")
    .attr("dy", ".3em")
    .style("text-anchor", "middle")
    .text(function(d) { return d.name.substring(0, d.r / 3); });
    node.append("text")
    .attr("dy", ".31em")
    .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
    .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
    .text(function(d) { return d.name; });
    });

    d3.select(self.frameElement).style("height", diameter + "px");
  19. @mbostock mbostock revised this gist Nov 13, 2012. 2 changed files with 26 additions and 30 deletions.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1 @@
    Bubble charts encode data in the area of circles. Although less perceptually-accurate than bar charts, they can pack hundreds of values into a small space. Implementation based on work by [Jeff Heer](http://jheer.org/). Data shows the [Flare](http://flare.prefuse.org/) class hierarchy, also courtesy Jeff Heer.
    Enclosure diagrams use containment to represent the hierarchy. Although circle packing is not as space-efficient as a treemap, it better reveals the hierarchy. Implementation based on work by [Jeff Heer](http://jheer.org/). Data shows the [Flare](http://flare.prefuse.org/) class hierarchy, also courtesy Jeff Heer.
    54 changes: 25 additions & 29 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,18 @@
    <meta charset="utf-8">
    <style>

    circle {
    fill: rgb(31, 119, 180);
    fill-opacity: .25;
    stroke: rgb(31, 119, 180);
    stroke-width: 1px;
    }

    .leaf circle {
    fill: #ff7f0e;
    fill-opacity: 1;
    }

    text {
    font: 10px sans-serif;
    }
    @@ -12,53 +24,37 @@
    <script>

    var diameter = 960,
    format = d3.format(",d"),
    color = d3.scale.category20c();
    format = d3.format(",d");

    var bubble = d3.layout.pack()
    .sort(null)
    .size([diameter, diameter])
    .padding(1.5);
    var pack = d3.layout.pack()
    .size([diameter - 4, diameter - 4])
    .value(function(d) { return d.size; });

    var svg = d3.select("body").append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
    .attr("class", "bubble");
    .append("g")
    .attr("transform", "translate(2,2)");

    d3.json("flare.json", function(error, root) {
    var node = svg.selectAll(".node")
    .data(bubble.nodes(classes(root))
    .filter(function(d) { return !d.children; }))
    var node = svg.datum(root).selectAll(".node")
    .data(pack.nodes)
    .enter().append("g")
    .attr("class", "node")
    .attr("class", function(d) { return d.children ? "node" : "leaf node"; })
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    node.append("title")
    .text(function(d) { return d.className + ": " + format(d.value); });
    .text(function(d) { return d.name + (d.children ? "" : ": " + format(d.size)); });

    node.append("circle")
    .attr("r", function(d) { return d.r; })
    .style("fill", function(d) { return color(d.packageName); });
    .attr("r", function(d) { return d.r; });

    node.append("text")
    node.filter(function(d) { return !d.children; }).append("text")
    .attr("dy", ".3em")
    .style("text-anchor", "middle")
    .text(function(d) { return d.className.substring(0, d.r / 3); });
    .text(function(d) { return d.name.substring(0, d.r / 3); });
    });

    // Returns a flattened hierarchy containing all leaf nodes under the root.
    function classes(root) {
    var classes = [];

    function recurse(name, node) {
    if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
    else classes.push({packageName: name, className: node.name, value: node.size});
    }

    recurse(null, root);
    return {children: classes};
    }

    d3.select(self.frameElement).style("height", diameter + "px");

    </script>
  20. @mbostock mbostock revised this gist Nov 13, 2012. 1 changed file with 7 additions and 5 deletions.
    12 changes: 7 additions & 5 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -11,18 +11,18 @@
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>

    var radius = 960,
    var diameter = 960,
    format = d3.format(",d"),
    color = d3.scale.category20c();

    var bubble = d3.layout.pack()
    .sort(null)
    .size([radius, radius])
    .size([diameter, diameter])
    .padding(1.5);

    var svg = d3.select("body").append("svg")
    .attr("width", radius)
    .attr("height", radius)
    .attr("width", diameter)
    .attr("height", diameter)
    .attr("class", "bubble");

    d3.json("flare.json", function(error, root) {
    @@ -59,4 +59,6 @@
    return {children: classes};
    }

    </script>
    d3.select(self.frameElement).style("height", diameter + "px");

    </script>
  21. @mbostock mbostock created this gist Nov 13, 2012.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    Bubble charts encode data in the area of circles. Although less perceptually-accurate than bar charts, they can pack hundreds of values into a small space. Implementation based on work by [Jeff Heer](http://jheer.org/). Data shows the [Flare](http://flare.prefuse.org/) class hierarchy, also courtesy Jeff Heer.
    380 changes: 380 additions & 0 deletions flare.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,380 @@
    {
    "name": "flare",
    "children": [
    {
    "name": "analytics",
    "children": [
    {
    "name": "cluster",
    "children": [
    {"name": "AgglomerativeCluster", "size": 3938},
    {"name": "CommunityStructure", "size": 3812},
    {"name": "HierarchicalCluster", "size": 6714},
    {"name": "MergeEdge", "size": 743}
    ]
    },
    {
    "name": "graph",
    "children": [
    {"name": "BetweennessCentrality", "size": 3534},
    {"name": "LinkDistance", "size": 5731},
    {"name": "MaxFlowMinCut", "size": 7840},
    {"name": "ShortestPaths", "size": 5914},
    {"name": "SpanningTree", "size": 3416}
    ]
    },
    {
    "name": "optimization",
    "children": [
    {"name": "AspectRatioBanker", "size": 7074}
    ]
    }
    ]
    },
    {
    "name": "animate",
    "children": [
    {"name": "Easing", "size": 17010},
    {"name": "FunctionSequence", "size": 5842},
    {
    "name": "interpolate",
    "children": [
    {"name": "ArrayInterpolator", "size": 1983},
    {"name": "ColorInterpolator", "size": 2047},
    {"name": "DateInterpolator", "size": 1375},
    {"name": "Interpolator", "size": 8746},
    {"name": "MatrixInterpolator", "size": 2202},
    {"name": "NumberInterpolator", "size": 1382},
    {"name": "ObjectInterpolator", "size": 1629},
    {"name": "PointInterpolator", "size": 1675},
    {"name": "RectangleInterpolator", "size": 2042}
    ]
    },
    {"name": "ISchedulable", "size": 1041},
    {"name": "Parallel", "size": 5176},
    {"name": "Pause", "size": 449},
    {"name": "Scheduler", "size": 5593},
    {"name": "Sequence", "size": 5534},
    {"name": "Transition", "size": 9201},
    {"name": "Transitioner", "size": 19975},
    {"name": "TransitionEvent", "size": 1116},
    {"name": "Tween", "size": 6006}
    ]
    },
    {
    "name": "data",
    "children": [
    {
    "name": "converters",
    "children": [
    {"name": "Converters", "size": 721},
    {"name": "DelimitedTextConverter", "size": 4294},
    {"name": "GraphMLConverter", "size": 9800},
    {"name": "IDataConverter", "size": 1314},
    {"name": "JSONConverter", "size": 2220}
    ]
    },
    {"name": "DataField", "size": 1759},
    {"name": "DataSchema", "size": 2165},
    {"name": "DataSet", "size": 586},
    {"name": "DataSource", "size": 3331},
    {"name": "DataTable", "size": 772},
    {"name": "DataUtil", "size": 3322}
    ]
    },
    {
    "name": "display",
    "children": [
    {"name": "DirtySprite", "size": 8833},
    {"name": "LineSprite", "size": 1732},
    {"name": "RectSprite", "size": 3623},
    {"name": "TextSprite", "size": 10066}
    ]
    },
    {
    "name": "flex",
    "children": [
    {"name": "FlareVis", "size": 4116}
    ]
    },
    {
    "name": "physics",
    "children": [
    {"name": "DragForce", "size": 1082},
    {"name": "GravityForce", "size": 1336},
    {"name": "IForce", "size": 319},
    {"name": "NBodyForce", "size": 10498},
    {"name": "Particle", "size": 2822},
    {"name": "Simulation", "size": 9983},
    {"name": "Spring", "size": 2213},
    {"name": "SpringForce", "size": 1681}
    ]
    },
    {
    "name": "query",
    "children": [
    {"name": "AggregateExpression", "size": 1616},
    {"name": "And", "size": 1027},
    {"name": "Arithmetic", "size": 3891},
    {"name": "Average", "size": 891},
    {"name": "BinaryExpression", "size": 2893},
    {"name": "Comparison", "size": 5103},
    {"name": "CompositeExpression", "size": 3677},
    {"name": "Count", "size": 781},
    {"name": "DateUtil", "size": 4141},
    {"name": "Distinct", "size": 933},
    {"name": "Expression", "size": 5130},
    {"name": "ExpressionIterator", "size": 3617},
    {"name": "Fn", "size": 3240},
    {"name": "If", "size": 2732},
    {"name": "IsA", "size": 2039},
    {"name": "Literal", "size": 1214},
    {"name": "Match", "size": 3748},
    {"name": "Maximum", "size": 843},
    {
    "name": "methods",
    "children": [
    {"name": "add", "size": 593},
    {"name": "and", "size": 330},
    {"name": "average", "size": 287},
    {"name": "count", "size": 277},
    {"name": "distinct", "size": 292},
    {"name": "div", "size": 595},
    {"name": "eq", "size": 594},
    {"name": "fn", "size": 460},
    {"name": "gt", "size": 603},
    {"name": "gte", "size": 625},
    {"name": "iff", "size": 748},
    {"name": "isa", "size": 461},
    {"name": "lt", "size": 597},
    {"name": "lte", "size": 619},
    {"name": "max", "size": 283},
    {"name": "min", "size": 283},
    {"name": "mod", "size": 591},
    {"name": "mul", "size": 603},
    {"name": "neq", "size": 599},
    {"name": "not", "size": 386},
    {"name": "or", "size": 323},
    {"name": "orderby", "size": 307},
    {"name": "range", "size": 772},
    {"name": "select", "size": 296},
    {"name": "stddev", "size": 363},
    {"name": "sub", "size": 600},
    {"name": "sum", "size": 280},
    {"name": "update", "size": 307},
    {"name": "variance", "size": 335},
    {"name": "where", "size": 299},
    {"name": "xor", "size": 354},
    {"name": "_", "size": 264}
    ]
    },
    {"name": "Minimum", "size": 843},
    {"name": "Not", "size": 1554},
    {"name": "Or", "size": 970},
    {"name": "Query", "size": 13896},
    {"name": "Range", "size": 1594},
    {"name": "StringUtil", "size": 4130},
    {"name": "Sum", "size": 791},
    {"name": "Variable", "size": 1124},
    {"name": "Variance", "size": 1876},
    {"name": "Xor", "size": 1101}
    ]
    },
    {
    "name": "scale",
    "children": [
    {"name": "IScaleMap", "size": 2105},
    {"name": "LinearScale", "size": 1316},
    {"name": "LogScale", "size": 3151},
    {"name": "OrdinalScale", "size": 3770},
    {"name": "QuantileScale", "size": 2435},
    {"name": "QuantitativeScale", "size": 4839},
    {"name": "RootScale", "size": 1756},
    {"name": "Scale", "size": 4268},
    {"name": "ScaleType", "size": 1821},
    {"name": "TimeScale", "size": 5833}
    ]
    },
    {
    "name": "util",
    "children": [
    {"name": "Arrays", "size": 8258},
    {"name": "Colors", "size": 10001},
    {"name": "Dates", "size": 8217},
    {"name": "Displays", "size": 12555},
    {"name": "Filter", "size": 2324},
    {"name": "Geometry", "size": 10993},
    {
    "name": "heap",
    "children": [
    {"name": "FibonacciHeap", "size": 9354},
    {"name": "HeapNode", "size": 1233}
    ]
    },
    {"name": "IEvaluable", "size": 335},
    {"name": "IPredicate", "size": 383},
    {"name": "IValueProxy", "size": 874},
    {
    "name": "math",
    "children": [
    {"name": "DenseMatrix", "size": 3165},
    {"name": "IMatrix", "size": 2815},
    {"name": "SparseMatrix", "size": 3366}
    ]
    },
    {"name": "Maths", "size": 17705},
    {"name": "Orientation", "size": 1486},
    {
    "name": "palette",
    "children": [
    {"name": "ColorPalette", "size": 6367},
    {"name": "Palette", "size": 1229},
    {"name": "ShapePalette", "size": 2059},
    {"name": "SizePalette", "size": 2291}
    ]
    },
    {"name": "Property", "size": 5559},
    {"name": "Shapes", "size": 19118},
    {"name": "Sort", "size": 6887},
    {"name": "Stats", "size": 6557},
    {"name": "Strings", "size": 22026}
    ]
    },
    {
    "name": "vis",
    "children": [
    {
    "name": "axis",
    "children": [
    {"name": "Axes", "size": 1302},
    {"name": "Axis", "size": 24593},
    {"name": "AxisGridLine", "size": 652},
    {"name": "AxisLabel", "size": 636},
    {"name": "CartesianAxes", "size": 6703}
    ]
    },
    {
    "name": "controls",
    "children": [
    {"name": "AnchorControl", "size": 2138},
    {"name": "ClickControl", "size": 3824},
    {"name": "Control", "size": 1353},
    {"name": "ControlList", "size": 4665},
    {"name": "DragControl", "size": 2649},
    {"name": "ExpandControl", "size": 2832},
    {"name": "HoverControl", "size": 4896},
    {"name": "IControl", "size": 763},
    {"name": "PanZoomControl", "size": 5222},
    {"name": "SelectionControl", "size": 7862},
    {"name": "TooltipControl", "size": 8435}
    ]
    },
    {
    "name": "data",
    "children": [
    {"name": "Data", "size": 20544},
    {"name": "DataList", "size": 19788},
    {"name": "DataSprite", "size": 10349},
    {"name": "EdgeSprite", "size": 3301},
    {"name": "NodeSprite", "size": 19382},
    {
    "name": "render",
    "children": [
    {"name": "ArrowType", "size": 698},
    {"name": "EdgeRenderer", "size": 5569},
    {"name": "IRenderer", "size": 353},
    {"name": "ShapeRenderer", "size": 2247}
    ]
    },
    {"name": "ScaleBinding", "size": 11275},
    {"name": "Tree", "size": 7147},
    {"name": "TreeBuilder", "size": 9930}
    ]
    },
    {
    "name": "events",
    "children": [
    {"name": "DataEvent", "size": 2313},
    {"name": "SelectionEvent", "size": 1880},
    {"name": "TooltipEvent", "size": 1701},
    {"name": "VisualizationEvent", "size": 1117}
    ]
    },
    {
    "name": "legend",
    "children": [
    {"name": "Legend", "size": 20859},
    {"name": "LegendItem", "size": 4614},
    {"name": "LegendRange", "size": 10530}
    ]
    },
    {
    "name": "operator",
    "children": [
    {
    "name": "distortion",
    "children": [
    {"name": "BifocalDistortion", "size": 4461},
    {"name": "Distortion", "size": 6314},
    {"name": "FisheyeDistortion", "size": 3444}
    ]
    },
    {
    "name": "encoder",
    "children": [
    {"name": "ColorEncoder", "size": 3179},
    {"name": "Encoder", "size": 4060},
    {"name": "PropertyEncoder", "size": 4138},
    {"name": "ShapeEncoder", "size": 1690},
    {"name": "SizeEncoder", "size": 1830}
    ]
    },
    {
    "name": "filter",
    "children": [
    {"name": "FisheyeTreeFilter", "size": 5219},
    {"name": "GraphDistanceFilter", "size": 3165},
    {"name": "VisibilityFilter", "size": 3509}
    ]
    },
    {"name": "IOperator", "size": 1286},
    {
    "name": "label",
    "children": [
    {"name": "Labeler", "size": 9956},
    {"name": "RadialLabeler", "size": 3899},
    {"name": "StackedAreaLabeler", "size": 3202}
    ]
    },
    {
    "name": "layout",
    "children": [
    {"name": "AxisLayout", "size": 6725},
    {"name": "BundledEdgeRouter", "size": 3727},
    {"name": "CircleLayout", "size": 9317},
    {"name": "CirclePackingLayout", "size": 12003},
    {"name": "DendrogramLayout", "size": 4853},
    {"name": "ForceDirectedLayout", "size": 8411},
    {"name": "IcicleTreeLayout", "size": 4864},
    {"name": "IndentedTreeLayout", "size": 3174},
    {"name": "Layout", "size": 7881},
    {"name": "NodeLinkTreeLayout", "size": 12870},
    {"name": "PieLayout", "size": 2728},
    {"name": "RadialTreeLayout", "size": 12348},
    {"name": "RandomLayout", "size": 870},
    {"name": "StackedAreaLayout", "size": 9121},
    {"name": "TreeMapLayout", "size": 9191}
    ]
    },
    {"name": "Operator", "size": 2490},
    {"name": "OperatorList", "size": 5248},
    {"name": "OperatorSequence", "size": 4190},
    {"name": "OperatorSwitch", "size": 2581},
    {"name": "SortOperator", "size": 2023}
    ]
    },
    {"name": "Visualization", "size": 16540}
    ]
    }
    ]
    }
    62 changes: 62 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,62 @@
    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>

    text {
    font: 10px sans-serif;
    }

    </style>
    <body>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script>

    var radius = 960,
    format = d3.format(",d"),
    color = d3.scale.category20c();

    var bubble = d3.layout.pack()
    .sort(null)
    .size([radius, radius])
    .padding(1.5);

    var svg = d3.select("body").append("svg")
    .attr("width", radius)
    .attr("height", radius)
    .attr("class", "bubble");

    d3.json("flare.json", function(error, root) {
    var node = svg.selectAll(".node")
    .data(bubble.nodes(classes(root))
    .filter(function(d) { return !d.children; }))
    .enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

    node.append("title")
    .text(function(d) { return d.className + ": " + format(d.value); });

    node.append("circle")
    .attr("r", function(d) { return d.r; })
    .style("fill", function(d) { return color(d.packageName); });

    node.append("text")
    .attr("dy", ".3em")
    .style("text-anchor", "middle")
    .text(function(d) { return d.className.substring(0, d.r / 3); });
    });

    // Returns a flattened hierarchy containing all leaf nodes under the root.
    function classes(root) {
    var classes = [];

    function recurse(name, node) {
    if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
    else classes.push({packageName: name, className: node.name, value: node.size});
    }

    recurse(null, root);
    return {children: classes};
    }

    </script>