和弦图中的颜色过渡平滑

时间:2020-10-16 12:33:24

标签: javascript d3.js colors chord-diagram

我用这个https://www.d3-graph-gallery.com/graph/chord_colors.html创建了一个和弦图。但是我不喜欢组之间链接的颜色只有一种颜色。因此决定将其平滑地从第一组的颜色过渡到第二组的颜色。我的代码看起来像这样。

   svg.datum(res)
  .append("g")
  .selectAll("path")
  .data(function(d) { return d; })
  .enter()
  .append("path")
    .attr("d", d3.ribbon()
      .radius(200)
    )
    .style("fill", function(d){ 
     
       //make a color transition
       return (d3.scaleLinear()
         .domain([0, 2])
         .range([colors[d.source.index], colors[d.target.index]])
         .interpolate(d3.interpolateHcl))
    
    }) // colors depend on the source group. Change to target otherwise.
    .style("stroke", "black");

但是它似乎不起作用,因为现在组之间的链接全都是黑色的。谁能帮我解决这个问题?

// create the svg area
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("width", 440)
  .attr("height", 440)
  .append("g")
  .attr("transform", "translate(220,220)")

// create a matrix
var matrix = [
  [0, 5871, 8916, 2868],
  [1951, 0, 2060, 6171],
  [8010, 16145, 0, 8045],
  [1013, 990, 940, 0]
];

// 4 groups, so create a vector of 4 colors
var colors = ["#440154ff", "#31668dff", "#37b578ff", "#fde725ff"]

// give this matrix to d3.chord(): it will calculates all the info we need to draw arc and ribbon
var res = d3.chord()
  .padAngle(0.05)
  .sortSubgroups(d3.descending)
  (matrix)

// add the groups on the outer part of the circle
svg
  .datum(res)
  .append("g")
  .selectAll("g")
  .data(function(d) {
    return d.groups;
  })
  .enter()
  .append("g")
  .append("path")
  .style("fill", function(d, i) {
    return colors[i]
  })
  .style("stroke", "black")
  .attr("d", d3.arc()
    .innerRadius(200)
    .outerRadius(210)
  )

// Add the links between groups
svg
  .datum(res)
  .append("g")
  .selectAll("path")
  .data(function(d) {
    return d;
  })
  .enter()
  .append("path")
  .attr("d", d3.ribbon()
    .radius(200)
  )
  .style("fill", function(d) {
    return (colors[d.source.index])
  }) // colors depend on the source group. Change to target otherwise.
  .style("stroke", "black");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id="my_dataviz"></div>

1 个答案:

答案 0 :(得分:0)

您可以使用radial gradients。与线性渐变形成一个从一种颜色到另一种颜色的正方形不同,径向渐变在每个方向上都发生变化。这对于曲线非常有用,因为它们的唯一常数是它们趋向于远离源而不是距离方向。

我为每个链接放置了一个径向渐变,在每个源上都有一个中心,并在每个方向上将颜色更改为目标的颜色。这样,每个和弦在逻辑方向上都有清晰的渐变。

const size = 440;

// create the svg area
var svg = d3.select("#my_dataviz")
  .append("svg")
  .attr("width", size)
  .attr("height", size)
  .append("g")
  .attr("transform", "translate(" + (size / 2) + ", " + (size / 2) + ")");

var defs = svg.append('defs');

// create a matrix
var matrix = [
  [0, 5871, 8916, 2868],
  [1951, 0, 2060, 6171],
  [8010, 16145, 0, 8045],
  [1013, 990, 940, 0]
];

// 4 groups, so create a vector of 4 colors
var colors = ["#440154ff", "#31668dff", "#37b578ff", "#fde725ff"]

// give this matrix to d3.chord(): it will calculates all the info we need to draw arc and ribbon
var res = d3.chord()
  .padAngle(0.05)
  .sortSubgroups(d3.descending)
  (matrix)

// add the groups on the outer part of the circle
svg
  .datum(res)
  .append("g")
  .selectAll("g")
  .data(function(d) {
    return d.groups;
  })
  .enter()
  .append("g")
  .append("path")
  .style("fill", function(d, i) {
    return colors[i]
  })
  .style("stroke", "black")
  .attr("d", d3.arc()
    .innerRadius(size / 2 - 20)
    .outerRadius(size / 2 - 10)
  )

// Add one gradient for each link
var gradient = defs.selectAll("radialGradient")
  .data(res)
  .enter()
  .append("radialGradient")
  .attr("id", function(d) {
    return "gradient-" + d.source.index + '-' + d.target.index;
  })
  .each(function(d) {
    var centerAngle = (d.source.endAngle - d.source.startAngle) / 2;
    centerAngle += d.source.startAngle;
    const radius = 0.5;

    d3.select(this)
      .attr('cx', function() {
        return Math.sin(centerAngle) * radius + 0.5;
      })
      .attr('cy', function() {
        return -Math.cos(centerAngle) * radius + 0.5;
      })
      .attr('r', 1);
  });

gradient.append("stop")
  .attr('class', 'start')
  .attr("offset", "0%")
  .attr("stop-color", function(d) {
    return colors[d.source.index];
  })
  .attr("stop-opacity", 1);

gradient.append("stop")
  .attr('class', 'end')
  .attr("offset", "100%")
  .attr("stop-color", function(d) {
    return colors[d.target.index];
  })
  .attr("stop-opacity", 1);

// Add the links between groups
svg
  .datum(res)
  .append("g")
  .selectAll("path")
  .data(function(d) {
    return d;
  })
  .enter()
  .append("path")
  .attr("d", d3.ribbon()
    .radius(size / 2 - 20)
  )
  .style("fill", function(d) {
    return "url(#gradient-" + d.source.index + '-' + d.target.index + ")";
  }) // colors depend on the source group. Change to target otherwise.
  .style("stroke", "black");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<div id="my_dataviz"></div>