Improving D3 Sequence Sunburst Example

天大地大妈咪最大 提交于 2019-12-21 12:25:38

问题


This D3 example served as my starting point:

http://bl.ocks.org/kerryrodden/7090426


I wanted to change data that feeds the diagram, and I made following new example:

http://jsfiddle.net/ZGVK3/

One can notice at least two problems:

  1. Legend is wrong. This is because it still contains 'hardcoded' names from original example.
  2. All nodes are colored black. This is because the color scheme is also 'hardcoded' only for node names from original example.

How to improve the original example (or my jsfiddle, it doesn't matter) so that legend and coloring are self-adjusted to the data that feeds the diagram?


回答1:


You can use an ordinal scale to map colors to the different node names. Implementing it would only require a few minor changes to your existing code.

Step 1. Create an ordinal scale for the colors

Instead of having colors be simply a list of color names, hard-coded to specific names, use d3.scale.ordinal(), and set the .range() to be an array of the colors you want to use. For example:

var colors = d3.scale.ordinal()
  .range(["#5687d1","#7b615c","#de783b","#6ab975","#a173d1","#bbbbbb"]);

This would create an ordinal scale that uses the same colors as the original visualization. Since your data would require more colors, you would want to add a few more to your range, otherwise colors will be repeated.

As a shortcut, you can use d3.scale.category20() to let d3 choose a range 20 categorical colors for you.

Now when setting the fill colors for your path element arcs and also your breadcrumbs, you would simply use colors(d.name) instead of colors[d.name].

Step 2. Use your data to construct the domain of the scale

The .domain() of this scale will be set once we have the data, since it will depend on a list of the unique names contained in the data. To do this, we can loop through the data, and create an array of the unique names. There are probably several ways to do this, but here's one that works well:

var uniqueNames = (function(a) {
  var output = [];
  a.forEach(function(d) {
    if (output.indexOf(d.name) === -1) {
      output.push(d.name);
    }
  });
  return output;
})(nodes);

This creates an empty array, then loops through each element of the nodes array and if the node's name doesn't already exist in the new array, it is added.

Then you can simply set the new array to be the domain of the color scale:

colors.domain(uniqueNames);

Step 3. Use the scale's domain to build the legend

Since the legend is going to depend on the domain, make sure the drawLegend() function is called after the domain is set.

You can find the number of elements in the domain (for setting the height of the legend) by calling colors.domain().length. Then for the legend's .data(), you can use the domain itself. Finally, to set the fill color for the legend boxes, you call the color scale on d since each element in the domain is a name. Here's what those three changes to the legend look like in practice:

var legend = d3.select("#legend").append("svg:svg")
  .attr("width", li.w)
  .attr("height", colors.domain().length * (li.h + li.s));

var g = legend.selectAll("g")
  .data(colors.domain())
  .enter().append("svg:g")
  .attr("transform", function(d, i) {
     return "translate(0," + i * (li.h + li.s) + ")";
  });

g.append("svg:rect")
  .attr("rx", li.r)
  .attr("ry", li.r)
  .attr("width", li.w)
  .attr("height", li.h)
  .style("fill", function(d) { return colors(d); });

And that's about it. Hope that helps.

Here's the updated JSFiddle.



来源:https://stackoverflow.com/questions/24582083/improving-d3-sequence-sunburst-example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!