D3 自定义曲线:区域的束插值

D3 custom curve: bundle interpolation for areas

考虑这个使用 基础 插值的 D3JS 图:

在 D3JS v3 中,我可以在区域上使用 bundle 插值 (.interpolate("bundle").tension(0)) 来实现这种类型的渲染:

注意图形的每个部分如何与其相邻部分很好地吻合。这就是我需要的。

对于 D3JS v4 和 v5,包插值的语法现在是这样的:.curve(d3.curveBundle)。但是,现在 "intended to work with d3.line, not d3.area."

我最近从 v3 升级到 v5,所以我尝试创建一个自定义束曲线,它也适用于区域,以保持我喜欢的插值类型v3.

我很亲近。这是我目前所拥有的:

///////////////////// Custom curves.

/** Bundle-ish.
 * Trying to adapt curveBundle for use with areas…
 */
function myBundle(context, beta) {
 this._basis = new d3.curveBasis(context);
 this._beta = beta;

 this._context = context; // temporary. shouldn't be needed for bundle.
}
myBundle.prototype = {

 areaStart: function() {
  this._line = 0;
 },
 areaEnd: function() {
  this._line = NaN;
 },
 lineStart: function() {
  this._x = [];
  this._y = [];
  this._basis.lineStart();
 },
 lineEnd: function() {
  var x = this._x,
    y = this._y,
    j = x.length - 1;

  if (j > 0) {
   var x0 = x[0],
     y0 = y[0],
     dx = x[j] - x0,
     dy = y[j] - y0,
     i = -1,
     t;

   while (++i <= j) {
    t = i / j;
    this._basis.point(
     this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
     this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
    );
   }
  }

  this._x = this._y = null;
  this._basis.lineEnd();
 },
 point: function(x, y) {
  this._x.push(+x);
  this._y.push(+y);
  // console.log( this._x.push(+x), this._y.push(+y) );
 }
};
myCurveBundle = (function custom(beta) {
 function myCurveBundle(context) {
  return beta === 1 ? new myBasis(context) : new myBundle(context, beta);
 }

 myCurveBundle.beta = function(beta) {
  return custom(+beta);
 };

 return myCurveBundle;
})(0.85);






///////////////////// The chart.

 var width = 960;
 var height = 540;
 var data = [];
 data.prosody = [116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.578, 125.552, 134.888, 144.225, 153.561, 162.898, 172.235, 181.571, 190.908, 200.244, 209.581, 218.917, 227.715, 218.849, 209.591, 200.333, 191.076, 181.818, 172.560, 163.302, 154.044, 144.787, 135.529, 126.271, 117.013, 107.755, 98.498, 89.240, 97.511, 118.857, 140.202, 161.547, 182.893, 192.100, 188.997, 185.895, 182.792, 179.690, 176.587, 173.485, 170.382, 167.280, 164.177, 161.075, 157.972, 154.870, 151.767, 148.665, 145.562, 142.460, 139.357, 136.255, 133.152, 130.050, 126.947, 124.244, 122.275, 120.307, 118.338, 116.369, 114.400, 112.431, 110.462, 108.493, 106.524, 104.555, 102.586, 100.617, 98.648, 99.659, 101.531, 103.402, 105.273, 107.145, 109.016, 110.887, 112.758, 114.630, 116.501, 118.372, 120.244, 122.115, 123.986, 125.857, 127.729, 129.600, 131.471, 133.343, 135.214, 137.085, 138.956, 140.828, 142.699, 144.570, 146.442, 148.313, 150.184, 149.175, 146.384, 143.594, 140.803, 138.013, 135.222, 132.432, 129.642, 126.851, 124.061, 121.270, 118.480, 115.689, 112.899, 110.109, 107.318, 104.528, 101.737, 98.947, 96.156, 93.366, 90.576, 87.785, 84.995, 82.204, 79.414, 76.623, 0, 0, 0, 0, 0, 0, 76.601, 78.414, 80.227, 82.041, 83.854, 85.667, 87.480, 89.294, 91.107, 92.920, 94.733, 96.547, 98.360, 100.173, 101.986, 103.800, 105.613, 107.426, 109.239, 111.053, 112.866, 114.679, 116.492, 115.917, 114.338, 112.760, 111.181, 109.602, 108.023, 106.444, 104.865, 103.286, 101.707, 100.128, 98.549, 96.970, 95.391, 93.812, 92.233, 90.654, 89.075, 87.534, 88.055, 88.646, 89.237, 89.827, 90.418, 91.009, 91.600, 92.191, 92.782, 93.373, 93.964, 94.555, 95.146, 95.737, 96.328, 96.919, 97.509, 98.100, 98.691, 99.282, 99.873, 100.062, 98.230, 96.399, 94.567, 92.736, 90.904, 89.072, 87.241, 85.409, 83.578, 81.746, 79.914, 78.083, 78.839, 80.880, 82.922, 84.964, 87.006, 89.048, 91.090, 93.132, 95.174, 97.216, 99.257, 101.299, 103.341, 105.383, 107.425, 109.467, 111.509, 113.551, 112.633, 110.755, 108.877, 106.999, 105.121, 103.243, 101.365, 99.487, 97.609, 95.731, 93.853, 91.975, 90.097, 88.219, 86.341, 84.463, 82.585, 80.707, 78.829, 76.951, 78.067, 81.290, 84.513, 87.736, 90.958, 94.181, 97.404, 100.627, 103.849, 107.072, 110.295, 113.517, 116.740, 119.963, 123.186, 126.408, 129.631, 132.854, 136.077, 139.299, 142.522, 145.745, 148.968, 152.190, 155.413, 154.840, 152.899, 150.958, 149.017, 147.076, 145.135, 143.194, 141.253, 139.312, 137.371, 135.429, 133.488, 131.547, 129.606, 127.665, 125.724, 124.874, 126.734, 128.594, 130.454, 132.314, 134.174, 136.034, 137.894, 139.754, 141.614, 143.474, 145.334, 147.194, 149.054, 150.914, 152.774, 154.634, 156.494, 158.354, 160.214, 162.074, 163.934, 165.664, 161.795, 157.761, 153.726, 149.692, 145.658, 141.624, 137.589, 133.555, 129.521, 125.487, 121.452, 117.418, 113.384, 109.350, 105.316, 101.281, 97.247, 93.213, 89.179, 85.144, 81.110, 77.076, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
 data.TextGrid = {  "phone" : [ /** segment type, beginning, and end of each segment **/ [ "sp", 0.0124716553288, 0.271882086168 ], [ "M", 0.271882086168, 0.401587301587 ], [ "OW", 0.401587301587, 0.521315192744 ], [ "S", 0.521315192744, 0.660997732426 ], [ "T", 0.660997732426, 0.710884353741 ], [ "AH", 0.710884353741, 0.760770975057 ], [ "V", 0.760770975057, 0.820634920635 ], [ "DH", 0.820634920635, 0.860544217687 ], [ "IY", 0.860544217687, 0.940362811791 ], [ "AH", 0.940362811791, 0.980272108844 ], [ "D", 0.980272108844, 1.04013605442 ], [ "V", 1.04013605442, 1.10997732426 ], [ "EH", 1.10997732426, 1.21972789116 ], [ "N", 1.21972789116, 1.289569161 ], [ "CH", 1.289569161, 1.42925170068 ], [ "ER", 1.42925170068, 1.51904761905 ], [ "Z", 1.51904761905, 1.57891156463 ], [ "R", 1.57891156463, 1.66870748299 ], [ "AH", 1.66870748299, 1.69863945578 ], [ "K", 1.69863945578, 1.75850340136 ], [ "AO", 1.75850340136, 1.88820861678 ], [ "R", 1.88820861678, 1.91814058957 ], [ "D", 1.91814058957, 1.95804988662 ], [ "AH", 1.95804988662, 1.99795918367 ], [ "D", 1.99795918367, 2.07777777778 ], [ "AH", 2.07777777778, 2.10770975057 ], [ "N", 2.10770975057, 2.18752834467 ], [ "DH", 2.18752834467, 2.22743764172 ], [ "AH", 2.22743764172, 2.2873015873 ], [ "S", 2.2873015873, 2.42698412698 ], [ "B", 2.42698412698, 2.51678004535 ], [ "UH", 2.51678004535, 2.68639455782 ], [ "K", 2.68639455782, 2.79614512472 ], [ "sp", 2.79614512472, 2.81609977324 ], [ "R", 2.81609977324, 2.95578231293 ], [ "IY", 2.95578231293, 3.00566893424 ], [ "L", 3.00566893424, 3.09546485261 ], [ "IY", 3.09546485261, 3.23514739229 ], [ "AH", 3.23514739229, 3.27505668934 ], [ "K", 3.27505668934, 3.41473922902 ], [ "ER", 3.41473922902, 3.68412698413 ], [ "D", 3.68412698413, 3.75396825397 ], [ "sp", 3.75396825397, 4.01337868481 ] ] }


 /**
  * Set up D3JS
  */
 var x = d3.scaleLinear()
  .domain([0, 401])
  .range([0, width]);
 var y = d3.scaleLinear()
  .domain([0, 800])
  .range([height, 0]);

 /** Center the stream vertically **/
 var shift = d3.scaleLinear()
  .domain([0, 0])
  .range([-height/2, 0]);

 /** Draw a stream segment **/
 var pathGenerator = d3.area()
  .curve( myCurveBundle.beta(0) )
  .x(function(d, i) { return x(i); })
  .y1(function(d) { return y(d + 72 ); }) /** 72 is just some arbitrary thickess given to the graph **/
  .y0(function(d) { return y(d); });

 var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height);



 /**
  * Render the chart
  */
 
 /** Draw the stream, on a per-segment basis **/
 var path = svg.selectAll("path")
  .data(data.TextGrid.phone)
  .enter().append("path")
   .attr("transform", function(d, i) { return "translate(" + x(Math.floor(d[1]*100)) + ", " + shift(i) + ")"; })
   .attr("class", function(d) { return "segment " + d[0]; })
   .on('click', function(d, i) { playFromTo(Math.floor(d[1] * 1000), Math.floor(d[2] * 1000)); })
   .attr("d", function(d) { return pathGenerator(data.prosody.slice( Math.floor(d[1]*100), Math.floor(d[2]*100)+1)); });
.segment { fill: #ccc; }
.segment.sp { display: none; }

/** Adapted from Margaret Horrigan for American English **/
.segment.IY { fill: #7AC141; }
.segment.IH { fill: #F9C5DC; }
.segment.UH { fill: #FF00FF; }
.segment.UW { fill: #0153A5; }
.segment.EY { fill: #8B8C90; }
.segment.EH { fill: #E61A25; }
.segment.AX { fill: #DF5435; }
.segment.ER { fill: #805EAA; }
.segment.AO { fill: #E2A856; }
.segment.OY { fill: #2E3094; }
.segment.OW { fill: #FC2B1C; }
.segment.AE { fill: #21201E; }
.segment.AH { fill: #DF5435; }
.segment.AA { fill: #bf181f; }
.segment.AY { fill: #FFFFFF; }
.segment.AW { fill: #7C4540; }
<script src="https://cdn.jsdelivr.net/npm/d3@5.4.0/dist/d3.min.js"></script>

(捆绑代码改编自 d3-shape 中的 bundle.js。)

非常接近:如果您检查 SVG,您会看到,即使没有显示任何内容,路径实际上也会创建。

如果您查看第一个 "visible" 段 (class segment M),您会发现它在某处包含一个 move 命令在中间:

M31.122194513715712,398.532825

如果我将它重命名为一行命令,就像这样:

L31.122194513715712,398.532825

...然后该段将显示。

我对自定义曲线的哪一部分负责这一点感到困惑。 如何将 M 变成 L?

生成的路径也恰好缺少最终的 Z。我将如何处理它?

关于 D3JS 中的自定义曲线,我没有找到太多帮助。欢迎任何帮助。

调用 areaStartareaEnd:

您似乎已经将 d3.curveBasis 中的 areaStartareaEnd 函数复制到您的自定义曲线中,该曲线主要来自 d3.curveBundle.

您不能只将 d3.curveBasis 中的代码复制到 d3.curveBundle 中,因为 this 指的是不同的东西。 this._basis(您的 d3.curveBasis 实例)无法访问 this._line(它期望 areaStartareaEnd 的变量,并且可以通过您的 customBundle).

您可以将 this._line 更改为 this._basis._line,但如果您注意到,d3.curveBundle 中的所有行函数都会调用它们各自的 this._basis 函数(例如 lineStart 调用 this._basis.lineStart())。如果你在这里做同样的事情,它应该是等价的:

areaStart: {
    // this._basis._line = 0; // this should work, for now
    this._basis.areaStart(); // but this makes more sense semantically
},
areaEnd: {
    // this._basis._line = NaN; // this should work, for now
    this._basis.areaEnd(); // but this makes more sense semantically
}

这样做的额外好处是,如果 d3.curveBasis 将来更改其实现,则兼容的可能性更高。

不需要new:

附带说明一下,在您的构造函数中,您使用 new 运算符创建了 this._basis 的新实例:

this._basis = new d3.curveBasis(context);

通过 newBasis 构造函数在 d3 模块内部使用,但在捆绑库中,它是一个函数构造函数。它可以只是:

this._basis = d3.curveBasis(context);

虽然使用 new 似乎没有破坏任何东西。有关详细信息,请参阅 。

您应该使用曲线束来渲染区域吗?

正如您所注意到的,d3.curveBundle 是 "intended to work with d3.line, not d3.area." 应该值得一问您是否应该使用 curveBundle 来渲染区域,因为遗漏似乎是故意的。来自 https://github.com/d3/d3-shape/issues/70,@mbostock 写道:

Correct, d3.curveBundle is only intended to work with d3.line. It’s for hierarchical edge bundling, not for rendering areas.

另见 https://github.com/d3/d3-shape#curveBundle

您可能应该将 curveBundle 与其他插值方法进行比较,看看使用它是否会以误导的方式扭曲您的区域。

结果:

总而言之,变化可见于此fiddle:https://jsfiddle.net/g4ya2qso/

或者:

或者,由于功能与 d3.curveBundle 非常相似,您可以只为 .areaStart.areaEnd 添加方法,并省略所有其他自定义代码,如下所示:

var myCurveBundle = (function custom(beta) {
    function myCustomBundle(context) {
      var bundle = d3.curveBundle.beta(beta)(context);
      bundle.areaStart = function () {
        bundle._basis.areaStart();
      };
      bundle.areaEnd = function () {
        bundle._basis.areaEnd();
      };
      return bundle;
    }
    myCustomBundle.beta = function(newBeta) {
      return custom(+newBeta);
    };
    return myCustomBundle;
})(0.85);

///////////////////// Custom curves.

/** Bundle-ish.
 * Trying to adapt curveBundle for use with areas…
 */
var myCurveBundle = (function custom(beta) {
  function myCustomBundle(context) {
    var bundle = d3.curveBundle.beta(beta)(context);
    bundle.areaStart = function () {
      bundle._basis.areaStart();
    };
    bundle.areaEnd = function () {
      bundle._basis.areaEnd();
    };
    return bundle;
  }
  myCustomBundle.beta = function(newBeta) {
    return custom(+newBeta);
  };
  return myCustomBundle;
})(0.85);

///////////////////// The chart.

 var width = 960;
 var height = 540;
 var data = [];
 data.prosody = [116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.578, 125.552, 134.888, 144.225, 153.561, 162.898, 172.235, 181.571, 190.908, 200.244, 209.581, 218.917, 227.715, 218.849, 209.591, 200.333, 191.076, 181.818, 172.560, 163.302, 154.044, 144.787, 135.529, 126.271, 117.013, 107.755, 98.498, 89.240, 97.511, 118.857, 140.202, 161.547, 182.893, 192.100, 188.997, 185.895, 182.792, 179.690, 176.587, 173.485, 170.382, 167.280, 164.177, 161.075, 157.972, 154.870, 151.767, 148.665, 145.562, 142.460, 139.357, 136.255, 133.152, 130.050, 126.947, 124.244, 122.275, 120.307, 118.338, 116.369, 114.400, 112.431, 110.462, 108.493, 106.524, 104.555, 102.586, 100.617, 98.648, 99.659, 101.531, 103.402, 105.273, 107.145, 109.016, 110.887, 112.758, 114.630, 116.501, 118.372, 120.244, 122.115, 123.986, 125.857, 127.729, 129.600, 131.471, 133.343, 135.214, 137.085, 138.956, 140.828, 142.699, 144.570, 146.442, 148.313, 150.184, 149.175, 146.384, 143.594, 140.803, 138.013, 135.222, 132.432, 129.642, 126.851, 124.061, 121.270, 118.480, 115.689, 112.899, 110.109, 107.318, 104.528, 101.737, 98.947, 96.156, 93.366, 90.576, 87.785, 84.995, 82.204, 79.414, 76.623, 0, 0, 0, 0, 0, 0, 76.601, 78.414, 80.227, 82.041, 83.854, 85.667, 87.480, 89.294, 91.107, 92.920, 94.733, 96.547, 98.360, 100.173, 101.986, 103.800, 105.613, 107.426, 109.239, 111.053, 112.866, 114.679, 116.492, 115.917, 114.338, 112.760, 111.181, 109.602, 108.023, 106.444, 104.865, 103.286, 101.707, 100.128, 98.549, 96.970, 95.391, 93.812, 92.233, 90.654, 89.075, 87.534, 88.055, 88.646, 89.237, 89.827, 90.418, 91.009, 91.600, 92.191, 92.782, 93.373, 93.964, 94.555, 95.146, 95.737, 96.328, 96.919, 97.509, 98.100, 98.691, 99.282, 99.873, 100.062, 98.230, 96.399, 94.567, 92.736, 90.904, 89.072, 87.241, 85.409, 83.578, 81.746, 79.914, 78.083, 78.839, 80.880, 82.922, 84.964, 87.006, 89.048, 91.090, 93.132, 95.174, 97.216, 99.257, 101.299, 103.341, 105.383, 107.425, 109.467, 111.509, 113.551, 112.633, 110.755, 108.877, 106.999, 105.121, 103.243, 101.365, 99.487, 97.609, 95.731, 93.853, 91.975, 90.097, 88.219, 86.341, 84.463, 82.585, 80.707, 78.829, 76.951, 78.067, 81.290, 84.513, 87.736, 90.958, 94.181, 97.404, 100.627, 103.849, 107.072, 110.295, 113.517, 116.740, 119.963, 123.186, 126.408, 129.631, 132.854, 136.077, 139.299, 142.522, 145.745, 148.968, 152.190, 155.413, 154.840, 152.899, 150.958, 149.017, 147.076, 145.135, 143.194, 141.253, 139.312, 137.371, 135.429, 133.488, 131.547, 129.606, 127.665, 125.724, 124.874, 126.734, 128.594, 130.454, 132.314, 134.174, 136.034, 137.894, 139.754, 141.614, 143.474, 145.334, 147.194, 149.054, 150.914, 152.774, 154.634, 156.494, 158.354, 160.214, 162.074, 163.934, 165.664, 161.795, 157.761, 153.726, 149.692, 145.658, 141.624, 137.589, 133.555, 129.521, 125.487, 121.452, 117.418, 113.384, 109.350, 105.316, 101.281, 97.247, 93.213, 89.179, 85.144, 81.110, 77.076, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
 data.TextGrid = {  "phone" : [ /** segment type, beginning, and end of each segment **/ [ "sp", 0.0124716553288, 0.271882086168 ], [ "M", 0.271882086168, 0.401587301587 ], [ "OW", 0.401587301587, 0.521315192744 ], [ "S", 0.521315192744, 0.660997732426 ], [ "T", 0.660997732426, 0.710884353741 ], [ "AH", 0.710884353741, 0.760770975057 ], [ "V", 0.760770975057, 0.820634920635 ], [ "DH", 0.820634920635, 0.860544217687 ], [ "IY", 0.860544217687, 0.940362811791 ], [ "AH", 0.940362811791, 0.980272108844 ], [ "D", 0.980272108844, 1.04013605442 ], [ "V", 1.04013605442, 1.10997732426 ], [ "EH", 1.10997732426, 1.21972789116 ], [ "N", 1.21972789116, 1.289569161 ], [ "CH", 1.289569161, 1.42925170068 ], [ "ER", 1.42925170068, 1.51904761905 ], [ "Z", 1.51904761905, 1.57891156463 ], [ "R", 1.57891156463, 1.66870748299 ], [ "AH", 1.66870748299, 1.69863945578 ], [ "K", 1.69863945578, 1.75850340136 ], [ "AO", 1.75850340136, 1.88820861678 ], [ "R", 1.88820861678, 1.91814058957 ], [ "D", 1.91814058957, 1.95804988662 ], [ "AH", 1.95804988662, 1.99795918367 ], [ "D", 1.99795918367, 2.07777777778 ], [ "AH", 2.07777777778, 2.10770975057 ], [ "N", 2.10770975057, 2.18752834467 ], [ "DH", 2.18752834467, 2.22743764172 ], [ "AH", 2.22743764172, 2.2873015873 ], [ "S", 2.2873015873, 2.42698412698 ], [ "B", 2.42698412698, 2.51678004535 ], [ "UH", 2.51678004535, 2.68639455782 ], [ "K", 2.68639455782, 2.79614512472 ], [ "sp", 2.79614512472, 2.81609977324 ], [ "R", 2.81609977324, 2.95578231293 ], [ "IY", 2.95578231293, 3.00566893424 ], [ "L", 3.00566893424, 3.09546485261 ], [ "IY", 3.09546485261, 3.23514739229 ], [ "AH", 3.23514739229, 3.27505668934 ], [ "K", 3.27505668934, 3.41473922902 ], [ "ER", 3.41473922902, 3.68412698413 ], [ "D", 3.68412698413, 3.75396825397 ], [ "sp", 3.75396825397, 4.01337868481 ] ] }

 /**
  * Set up D3JS
  */
 var x = d3.scaleLinear()
  .domain([0, 401])
  .range([0, width]);
 var y = d3.scaleLinear()
  .domain([0, 800])
  .range([height, 0]);

 /** Center the stream vertically **/
 var shift = d3.scaleLinear()
  .domain([0, 0])
  .range([-height/2, 0]);

 /** Draw a stream segment **/
 var pathGenerator = d3.area()
  .curve( myCurveBundle.beta(0) )
  .x(function(d, i) { return x(i); })
  .y1(function(d) { return y(d + 72 ); }) /** 72 is just some arbitrary thickess given to the graph **/
  .y0(function(d) { return y(d); });

 var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height);

 /**
  * Render the chart
  */
 
 /** Draw the stream, on a per-segment basis **/
 var path = svg.selectAll("path")
  .data(data.TextGrid.phone)
  .enter().append("path")
   .attr("transform", function(d, i) { return "translate(" + x(Math.floor(d[1]*100)) + ", " + shift(i) + ")"; })
   .attr("class", function(d) { return "segment " + d[0]; })
   .on('click', function(d, i) { playFromTo(Math.floor(d[1] * 1000), Math.floor(d[2] * 1000)); })
   .attr("d", function(d) { return pathGenerator(data.prosody.slice( Math.floor(d[1]*100), Math.floor(d[2]*100)+1)); });
.segment { fill: #ccc; }
.segment.sp { display: none; }

/** Adapted from Margaret Horrigan for American English **/
.segment.IY { fill: #7AC141; }
.segment.IH { fill: #F9C5DC; }
.segment.UH { fill: #FF00FF; }
.segment.UW { fill: #0153A5; }
.segment.EY { fill: #8B8C90; }
.segment.EH { fill: #E61A25; }
.segment.AX { fill: #DF5435; }
.segment.ER { fill: #805EAA; }
.segment.AO { fill: #E2A856; }
.segment.OY { fill: #2E3094; }
.segment.OW { fill: #FC2B1C; }
.segment.AE { fill: #21201E; }
.segment.AH { fill: #DF5435; }
.segment.AA { fill: #bf181f; }
.segment.AY { fill: #FFFFFF; }
.segment.AW { fill: #7C4540; }
<script src="https://cdn.jsdelivr.net/npm/d3@5.4.0/dist/d3.min.js"></script>