An experiment on treemap coloring, using color encoding for depth. Instead of regions, boundaries are colored. A categorical color scale is used to help find nodes at the same level in other parts of the map, while some padding between lines is used together with decreasing thickness to convey a sense of nesting.
| svg = d3.select('svg') | |
| width = svg.node().getBoundingClientRect().width | |
| height = svg.node().getBoundingClientRect().height | |
| size = Math.round(Math.min(width, height) * 0.8) | |
| boundary_thickness = d3.scale.sqrt() | |
| .range([3,0.5]) | |
| boundary_color = (i) -> d3.hcl(50+100*i,50,50) | |
| treemap = d3.layout.treemap() | |
| .size([size, size]) | |
| .value((node) -> node.size) | |
| # translate the viewBox to have (0,0) at the center of the vis | |
| svg | |
| .attr | |
| viewBox: "#{-width/2} #{-height/2} #{width} #{height}" | |
| # append a group for zoomable content | |
| zoomable_layer = svg.append('g') | |
| # define a zoom behavior | |
| zoom = d3.behavior.zoom() | |
| .scaleExtent([1,10]) # min-max zoom | |
| .on 'zoom', () -> | |
| # GEOMETRIC ZOOM | |
| zoomable_layer | |
| .attr | |
| transform: "translate(#{zoom.translate()})scale(#{zoom.scale()})" | |
| # bind the zoom behavior to the main SVG | |
| svg.call(zoom) | |
| # group the visualization | |
| vis = zoomable_layer.append('g') | |
| .attr | |
| transform: "translate(#{-size/2},#{-size/2})" | |
| d3.json 'http://wafi.iit.cnr.it/webvis/tmp/flare.json', (tree) -> | |
| data = treemap.nodes(tree) | |
| boundary_thickness | |
| .domain([d3.min(data, (d) -> d.depth), d3.max(data, (d) -> d.depth)]) | |
| levels_data = d3.nest() | |
| .key (d) -> d.depth | |
| .entries data | |
| levels_data.forEach (d) -> d.key = +d.key | |
| # drawing order: deep to shallow | |
| levels_data.sort (a,b) -> d3.descending(a.key,b.key) | |
| levels = vis.selectAll '.level' | |
| .data levels_data | |
| levels.enter().append 'g' | |
| .attr | |
| class: 'level' | |
| strips = levels.selectAll '.boundary_strip' | |
| .data (d) -> d.values | |
| enter_strips = strips.enter().append 'rect' | |
| .attr | |
| class: 'boundary_strip' | |
| x: (node) -> node.x | |
| y: (node) -> node.y | |
| width: (node) -> node.dx | |
| height: (node) -> node.dy | |
| 'stroke-width': (node) -> 12 | |
| lines = levels.selectAll '.boundary_line' | |
| .data (d) -> d.values | |
| enter_lines = lines.enter().append 'rect' | |
| .attr | |
| class: 'boundary_line' | |
| x: (node) -> node.x | |
| y: (node) -> node.y | |
| width: (node) -> node.dx | |
| height: (node) -> node.dy | |
| stroke: (node) -> boundary_color(node.depth) | |
| 'stroke-width': (node) -> boundary_thickness(node.depth) | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>Treemaps: boundary coloring</title> | |
| <link type="text/css" href="index.css" rel="stylesheet"/> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| </head> | |
| <body> | |
| <svg></svg> | |
| <script src="index.js"></script> | |
| </body> | |
| </html> |
| // Generated by CoffeeScript 1.10.0 | |
| (function() { | |
| var boundary_color, boundary_thickness, height, size, svg, treemap, vis, width, zoom, zoomable_layer; | |
| svg = d3.select('svg'); | |
| width = svg.node().getBoundingClientRect().width; | |
| height = svg.node().getBoundingClientRect().height; | |
| size = Math.round(Math.min(width, height) * 0.8); | |
| boundary_thickness = d3.scale.sqrt().range([3, 0.5]); | |
| boundary_color = function(i) { | |
| return d3.hcl(50 + 100 * i, 50, 50); | |
| }; | |
| treemap = d3.layout.treemap().size([size, size]).value(function(node) { | |
| return node.size; | |
| }); | |
| svg.attr({ | |
| viewBox: (-width / 2) + " " + (-height / 2) + " " + width + " " + height | |
| }); | |
| zoomable_layer = svg.append('g'); | |
| zoom = d3.behavior.zoom().scaleExtent([1, 10]).on('zoom', function() { | |
| return zoomable_layer.attr({ | |
| transform: "translate(" + (zoom.translate()) + ")scale(" + (zoom.scale()) + ")" | |
| }); | |
| }); | |
| svg.call(zoom); | |
| vis = zoomable_layer.append('g').attr({ | |
| transform: "translate(" + (-size / 2) + "," + (-size / 2) + ")" | |
| }); | |
| d3.json('http://wafi.iit.cnr.it/webvis/tmp/flare.json', function(tree) { | |
| var data, enter_lines, enter_strips, levels, levels_data, lines, strips; | |
| data = treemap.nodes(tree); | |
| boundary_thickness.domain([ | |
| d3.min(data, function(d) { | |
| return d.depth; | |
| }), d3.max(data, function(d) { | |
| return d.depth; | |
| }) | |
| ]); | |
| levels_data = d3.nest().key(function(d) { | |
| return d.depth; | |
| }).entries(data); | |
| levels_data.forEach(function(d) { | |
| return d.key = +d.key; | |
| }); | |
| levels_data.sort(function(a, b) { | |
| return d3.descending(a.key, b.key); | |
| }); | |
| levels = vis.selectAll('.level').data(levels_data); | |
| levels.enter().append('g').attr({ | |
| "class": 'level' | |
| }); | |
| strips = levels.selectAll('.boundary_strip').data(function(d) { | |
| return d.values; | |
| }); | |
| enter_strips = strips.enter().append('rect').attr({ | |
| "class": 'boundary_strip', | |
| x: function(node) { | |
| return node.x; | |
| }, | |
| y: function(node) { | |
| return node.y; | |
| }, | |
| width: function(node) { | |
| return node.dx; | |
| }, | |
| height: function(node) { | |
| return node.dy; | |
| }, | |
| 'stroke-width': function(node) { | |
| return 12; | |
| } | |
| }); | |
| lines = levels.selectAll('.boundary_line').data(function(d) { | |
| return d.values; | |
| }); | |
| return enter_lines = lines.enter().append('rect').attr({ | |
| "class": 'boundary_line', | |
| x: function(node) { | |
| return node.x; | |
| }, | |
| y: function(node) { | |
| return node.y; | |
| }, | |
| width: function(node) { | |
| return node.dx; | |
| }, | |
| height: function(node) { | |
| return node.dy; | |
| }, | |
| stroke: function(node) { | |
| return boundary_color(node.depth); | |
| }, | |
| 'stroke-width': function(node) { | |
| return boundary_thickness(node.depth); | |
| } | |
| }); | |
| }); | |
| }).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment