d3.js Sankey diagram: rectangles fill color

2020-02-08 21:42发布

问题:

So I am playing around with the d3.js Sankey diagram.

In this example (pictured above) color is defined using

var color = d3.scale.category20();

For each node there is a rectangle, and that rectangle is filled by altering the style:

.style("fill", function(d) {
    return d.color = color(d.name.replace(/ .*/, ""));
})

I'm looking for suggestions on using custom colors. If I wanted to use only say 6 colors, but have the node rectangle colors chosen based on a value in the .json file.

For example, lets say I wanted to show a snakey chart of teams in the NFL. The colours each represent which division the teams play in. So if they move to a different division, the color changes. And the nodes are created for every season. Something along those lines.

So is it possible to run the

node.append("rect")
    .attr("height", function(d) { return d.dy; })
    .attr("width", sankey.nodeWidth())
    .style("fill", function(d) {
        return d.color = color(d.name.replace(/ .*/, ""));
    })
    .style("stroke", function(d) {
        return d3.rgb(d.color).darker(2);
    })
   .append("title")
    .text(function(d) { return d.name + "\n" + format(d.value); });

with the color based on a value in the json file? I am thinking just an if statement, but is there an easier way? Could I just include the hex color code in the json?

回答1:

Sounds like you want to include the colour in the JSON in this case. You can include it in any way that the browser recognises, e.g. as a name ("white") or hex ("#fff"). See the SVG spec for a full list of supported colour specifications.



回答2:

Alternatively, you could map the colors to the division explicitly with a d3 ordinal scale as mentioned in the documentation. See Colorbrewer at the bottom.

var color = d3.scale.ordinal()
    .domain(["foo", "bar", "baz"])
    .range(["#fff","#000","#333"]);

and then

.attr("fill", function(d) { return color(d.division); });


回答3:

Replace const color = d3.scaleOrdinal(d3.schemeCategory20); with:

const color = d3.scaleOrdinal() 
.domain(["Crude oil","Natural gas",...])
.range(["#FD3E35","#FFCB06",...]);

And stay with:

.style('fill', (d,i) => {
  d.color = color(d.name.replace(/ .*/, ''));
  return d.color;})