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:
One can notice at least two problems:
- Legend is wrong. This is because it still contains 'hardcoded' names from original example.
- 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?
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, used3.scale.ordinal()
, and set the.range()
to be an array of the colors you want to use. For example: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 usecolors(d.name)
instead ofcolors[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: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:
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 ond
since each element in the domain is aname
. Here's what those three changes to the legend look like in practice:And that's about it. Hope that helps.
Here's the updated JSFiddle.