如何在D3中应用条件填充?

huangapple go评论72阅读模式
英文:

How to apply conditional filling in D3?

问题

// ++++++++++++++++++++++++++++++++++++++++ 这是常量变量,用于定义可视化的尺寸。width 和 height 变量定义了包含可视化的 SVG 元素的总体尺寸。margin 变量用于设置 SVG 元素和图表之间的边距。innerRadius 和 outerRadius 变量定义了用于表示数据的两个圆的半径。++++++++++++++++++++++++ */
const width = 954;
const height = width;
const margin = 10;
const innerRadius = width / 5;
const outerRadius = width / 2 - margin;
/* ++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++ +++++++++++++++++++++++++++++*/

// ++++++++++++++++++++++++++++++++++++++++ 步骤 1) 解析 CSV 文件 ++++++++++++++++++++++++++++
d3.csv("synthetic_data.csv", function(d) {
  // 解析 CSV 数据并返回一个具有所需属性的 JavaScript 对象
  return {
    DATE_TIME: new Date(d.DATE_TIME),
    VALUE1: +d.VALUE1,
    VALUE2: +d.VALUE2,
    INSPECTION: +d.INSPECTION,
  };
}).then(function(rawdata) {
  // 将 DATE_TIME 列转换为分钟精确时间
  rawdata.forEach(function(d) {
    const hour = d.DATE_TIME.getHours();
    const minute = d.DATE_TIME.getMinutes();
    d.minuteTime = hour * 60 + minute;
  });

  let rawdata2 = rawdata.filter(d => d.INSPECTION == 1);

  const minuteScale = d3.scaleLinear()
    .domain([0, 1439]) // 0 到 23:59 (24 小时 * 60 分钟,不减去 -1,否则改为 1439 - 1)
    .range([0, 2 * Math.PI]);

  const minuteTimeValues = rawdata2.map(d => d.minuteTime);

  const x = d3.scaleTime()
    .domain([0, 1439]) // 使用“minuteTime”值的范围设置域
    .range([0, 2 * Math.PI]); // 设置所需的范围

  console.log(rawdata)

  const minValue1 = d3.min(rawdata, d => d.VALUE1);
  const minValue2 = d3.min(rawdata, d => d.VALUE2);
  const maxValue1 = d3.max(rawdata, d => d.VALUE1);
  const maxValue2 = d3.max(rawdata, d => d.VALUE2);

  const yMin = minValue1 < minValue2 ? minValue1 : minValue2;
  const yMax = maxValue1 > maxValue2 ? maxValue1 : maxValue2;

  const y = d3.scaleLinear()
              .domain([yMin, yMax])
              .range([innerRadius, outerRadius]);

  // 修改 xAxis 生成器以仅显示小时并添加填充

  const xAxis = (g) => g
    .attr("font-family", "sans-serif")
    .attr("font-size", 10)
    .call((g) => g.selectAll("g")
      .data(d3.range(0, 24)) // 创建一个小时值数组
      .join("g")
        .each((d, i) => d.id = `hour-${i}`)
        .call((g) => g.append("path")
            .attr("stroke", "#000")
            .attr("stroke-opacity", 0.2)
            .attr("d", (d) => `
              M${d3.pointRadial(x(d * 60), innerRadius)}
              L${d3.pointRadial(x(d * 60), outerRadius)}
            `))
        .call((g) => g.append("path")
            .attr("id", (d) => `hour-${d}`)
            .datum((d) => [d * 60, (d + 1) * 60])
            .attr("fill", "none")
            .attr("d", ([a, b]) => `
              M${d3.pointRadial(x(a), innerRadius-10)}
              A${innerRadius},${innerRadius} 0,0,1 ${d3.pointRadial(x(b), innerRadius)}
            `))
        .call((g) => g.append("text")
          .append("textPath")
            .attr("startOffset", 6)
            .attr("href", (d) => `#hour-${d}`)
            .text((d) => d.toString().padStart(2, "0"))
            .attr("text-anchor", "middle")
            .attr("alignment-baseline", "middle")
            .attr("transform", (d) => {
              const angle = x(d * 60);
              const radius = innerRadius - 20; // 减小半径以将标签移近中心
              return `translate(${d3.pointRadial(x(d * 60), radius)})`;
            })
        )
    );

  const yAxis = g => g
    .attr("text-anchor", "middle")
    .attr("font-family", "sans-serif")
    .attr("font-size", 10)
    .call(g => g.selectAll("g")
      .data(y.ticks().reverse())
      .join("g")
      .attr("fill", "none")
      .call(g => g.append("circle")
        .attr("stroke", "#000")
        .attr("stroke-opacity", 0.2)
        .attr("r", y))
      .call(g => g.append("text")
        .attr("y", d => -y(d))
        .attr("dy", "0.35em")
        .attr("stroke", "#fff")
        .attr("stroke-width", 5)
        .text((x, i) => `${x.toFixed(0)}${i ? "" : ""}`)
        .clone(true)
          .attr("y", d => y(d))
        .selectAll(function() { return [this, this.previousSibling]; })
        .clone(true)
          .attr("fill", "currentColor")
          .attr("stroke", "none")));

  const line = d3.lineRadial()
                .curve(d3.curveLinearClosed)
                .angle(d => x(d.minuteTime));

  const area = d3.areaRadial()
                .curve(d3.curveLinearClosed)
                .angle(d => x(d.minuteTime))

  const svg = d3.create("svg")
    .attr("viewBox", [-width / 2, -height / 2, width, height])
    .attr("stroke-linejoin", "round")
    .attr("stroke-linecap", "round");

  svg.append("path")
    .attr("fill", "none")
    .attr("stroke", "red")
    .attr("stroke-width", 3)
    .attr("d", line
      .radius(d => y(d.VALUE1))
      (rawdata2));

  svg.append("path")
    .attr("fill", "none")
    .attr("stroke", "green")
    .attr("stroke-width", 3)
    .attr("d", line

<details>
<summary>英文:</summary>

My CSV file looks like this
```csv
DATE_TIME,ID,HOUR,MINUTE,VALUE1,VALUE2,TIME,INSPECTION,seconds
2018-11-01 00:00:00,1,0,0,131.8403388480975,163.40706930229611,00:00:00,1,0
2018-11-01 00:20:00,1,0,20,128.66143180880016,182.4166850946821,00:20:00,1,20
2018-11-01 00:40:00,1,0,40,157.9838672230082,177.12826879097582,00:40:00,1,40
2018-11-01 01:00:00,1,1,0,154.74491894762372,177.02056153432287,01:00:00,1,60
2018-11-01 01:20:00,1,1,20,145.17425322202857,170.28572211898428,01:20:00,1,80
2018-11-01 01:40:00,1,1,40,86.33692934233684,161.306233500133004,01:40:00,1,100
2018-11-01 02:00:00,1,2,0,157.70472270832147,175.57007397898963,02:00:00,1,120
2018-11-01 02:20:00,1,2,20,92.04378773072385,152.758855696098315,02:20:00,1,140
2018-11-01 02:40:00,1,2,40,94.91482763887929,164.34713115356462,02:40:00,1,160
2018-11-01 03:00:00,1,3,0,150.58752716935703,152.573995003487525,03:00:00,1,180
2018-11-01 03:20:00,1,3,20,147.64763286003245,181.7346317353725,03:20:00,1,200
2018-11-01 03:40:00,1,3,40,152.00311766772614,169.43438782829136,03:40:00,1,220
2018-11-01 04:00:00,1,4,0,90.67568616871652,165.94364405219294,04:00:00,1,240
2018-11-01 04:20:00,1,4,20,127.6260776280666,154.41327889693226,04:20:00,1,260
2018-11-01 04:40:00,1,4,40,88.35193693321801,86.7514997924824,04:40:00,1,280
2018-11-01 05:00:00,1,5,0,99.44723697225662,61.81705113015809,05:00:00,1,300
2018-11-01 05:20:00,1,5,20,153.28490595395064,70.71671056760238,05:20:00,1,320
2018-11-01 05:40:00,1,5,40,139.53124376248127,86.96902617467873,05:40:00,1,340
2018-11-01 06:00:00,1,6,0,144.5960580946409,53.46091762212306,06:00:00,1,360
2018-11-01 06:20:00,1,6,20,110.05611978038519,73.32550566412914,06:20:00,1,380
2018-11-01 06:40:00,1,6,40,151.21482961729612,50.858838256056316,06:40:00,1,400
2018-11-01 07:00:00,1,7,0,127.88766918064593,52.45266678876003,07:00:00,1,420
2018-11-01 07:20:00,1,7,20,148.72830141013,60.496196118302194,07:20:00,1,440
2018-11-01 07:40:00,1,7,40,83.62908148257569,86.54612924908034,07:40:00,1,460
2018-11-01 08:00:00,1,8,0,113.49475177931873,59.15439348393694,08:00:00,1,480
2018-11-01 08:20:00,1,8,20,139.37377082538475,86.1347823168292,08:20:00,1,500
2018-11-01 08:40:00,1,8,40,104.5216263376223,86.92624219265554,08:40:00,1,520
2018-11-01 09:00:00,1,9,0,152.55680056900144,60.938994790632144,09:00:00,1,540
2018-11-01 09:20:00,1,9,20,140.38896796205978,56.19504976107255,09:20:00,1,560
2018-11-01 09:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 10:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 11:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 12:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 13:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 14:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 15:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 16:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 17:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 18:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 19:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 20:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 21:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 22:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 23:40:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580
2018-11-01 23:59:00,1,9,40,135.79579769996855,62.50941443441722,09:40:00,1,580

I would like to apply conditional filling so that the area where VALUE1 value bigger than VALUE2 is blue, and VALUE2 value bigger than VALUE1 is gray. But, I end up seeing only gray color.

如何在D3中应用条件填充?

Here is my complete code:


&lt;!--

This is an HTML document that includes a D3.js script. It starts with the head section where the document&#39;s title, character encoding, and D3.js library are included. Then, the document&#39;s body starts with a header h1 tag, followed by a script tag where the D3.js code is written.

--&gt;

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;title&gt;D3 CSV Example&lt;/title&gt;
  &lt;script src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;

&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;D3 CSV Example&lt;/h1&gt;
  &lt;script&gt;

    /* ++++++++++++++++++++++++ These are constant variables that define the dimensions of the visualization. The width and height variables define the overall dimensions of the SVG element that will contain the visualization. The margin variable is used to set a margin between the SVG element and the chart. The innerRadius and outerRadius variables define the radii of the two circles that will be used to represent the data. ++++++++++++++++ */
    const width = 954;
    const height = width;
    const margin = 10;
    const innerRadius = width / 5;
    const outerRadius = width / 2 - margin;
    /* ++++++++++++++++++++++++++++++++++++++++++  +++++++++++++++++++++++ +++++++++++++++++++++++++++++*/

    // ++++++++++++++++++++++++++++++++++++++++ Step 1) Parsing the CSV file ++++++++++++++++++++++++++++
    d3.csv(&quot;synthetic_data.csv&quot;, function(d) {
      // Parse the CSV data and return a JavaScript object
      // with the desired properties
      return {
        DATE_TIME: new Date(d.DATE_TIME),
        VALUE1: +d.VALUE1,
        VALUE2: +d.VALUE2,
        INSPECTION: +d.INSPECTION,
      };
    }).then(function(rawdata) {
      // Convert DATE_TIME column to minute-precise time
      rawdata.forEach(function(d) {
        const hour = d.DATE_TIME.getHours();
        const minute = d.DATE_TIME.getMinutes();
        d.minuteTime = hour * 60 + minute;
      });

      let rawdata2 = rawdata.filter(d =&gt; d.INSPECTION == 1);

      const minuteScale = d3.scaleLinear()
        .domain([0, 1439]) // 0 to 23:59 (24 hours * 60 minutes without -1 or else change to 1439 //- 1)
        .range([0, 2 * Math.PI]);

      const minuteTimeValues = rawdata2.map(d =&gt; d.minuteTime);

      const x = d3.scaleTime()
        .domain([0, 1439]) // Set the domain using the extent of the &quot;minuteTime&quot; values
        .range([0, 2 * Math.PI]); // Set the desired range

      console.log(rawdata)

      const minValue1 = d3.min(rawdata, d =&gt; d.VALUE1);
      const minValue2 = d3.min(rawdata, d =&gt; d.VALUE2);
      const maxValue1 = d3.max(rawdata, d =&gt; d.VALUE1);
      const maxValue2 = d3.max(rawdata, d =&gt; d.VALUE2);

      const yMin = minValue1 &lt; minValue2 ? minValue1 : minValue2;
      const yMax = maxValue1 &gt; maxValue2 ? maxValue1 : maxValue2;

      const y = d3.scaleLinear()
                  .domain([yMin, yMax])
                  .range([innerRadius, outerRadius]);

// Modify the xAxis generator to display only the hour and add padding

const xAxis = (g) =&gt; g
  .attr(&quot;font-family&quot;, &quot;sans-serif&quot;)
  .attr(&quot;font-size&quot;, 10)
  .call((g) =&gt; g.selectAll(&quot;g&quot;)
    .data(d3.range(0, 24)) // create an array of hour values
    .join(&quot;g&quot;)
      .each((d, i) =&gt; d.id = `hour-${i}`)
      .call((g) =&gt; g.append(&quot;path&quot;)
          .attr(&quot;stroke&quot;, &quot;#000&quot;)
          .attr(&quot;stroke-opacity&quot;, 0.2)
          .attr(&quot;d&quot;, (d) =&gt; `
            M${d3.pointRadial(x(d * 60), innerRadius)}
            L${d3.pointRadial(x(d * 60), outerRadius)}
          `))
      .call((g) =&gt; g.append(&quot;path&quot;)
          .attr(&quot;id&quot;, (d) =&gt; `hour-${d}`)
          .datum((d) =&gt; [d * 60, (d + 1) * 60])
          .attr(&quot;fill&quot;, &quot;none&quot;)
          .attr(&quot;d&quot;, ([a, b]) =&gt; `
            M${d3.pointRadial(x(a), innerRadius-10)}
            A${innerRadius},${innerRadius} 0,0,1 ${d3.pointRadial(x(b), innerRadius)}
          `))
      .call((g) =&gt; g.append(&quot;text&quot;)
        .append(&quot;textPath&quot;)
          .attr(&quot;startOffset&quot;, 6)
          .attr(&quot;href&quot;, (d) =&gt; `#hour-${d}`)
          .text((d) =&gt; d.toString().padStart(2, &quot;0&quot;))
          .attr(&quot;text-anchor&quot;, &quot;middle&quot;)
          .attr(&quot;alignment-baseline&quot;, &quot;middle&quot;)
          .attr(&quot;transform&quot;, (d) =&gt; {
            const angle = x(d * 60);
            const radius = innerRadius - 20; // reduce the radius to move the labels closer to the center
                        return `translate(${d3.pointRadial(x(d * 60), radius)})`;
          })
      )
  );



      const yAxis = g =&gt; g
        .attr(&quot;text-anchor&quot;, &quot;middle&quot;)
        .attr(&quot;font-family&quot;, &quot;sans-serif&quot;)
        .attr(&quot;font-size&quot;, 10)
        .call(g =&gt; g.selectAll(&quot;g&quot;)
          .data(y.ticks().reverse())
          .join(&quot;g&quot;)
          .attr(&quot;fill&quot;, &quot;none&quot;)
          .call(g =&gt; g.append(&quot;circle&quot;)
            .attr(&quot;stroke&quot;, &quot;#000&quot;)
            .attr(&quot;stroke-opacity&quot;, 0.2)
            .attr(&quot;r&quot;, y))
          .call(g =&gt; g.append(&quot;text&quot;)
            .attr(&quot;y&quot;, d =&gt; -y(d))
            .attr(&quot;dy&quot;, &quot;0.35em&quot;)
            .attr(&quot;stroke&quot;, &quot;#fff&quot;)
            .attr(&quot;stroke-width&quot;, 5)
            .text((x, i) =&gt; `${x.toFixed(0)}${i ? &quot;&quot; : &quot;&quot;}`)
          .clone(true)
            .attr(&quot;y&quot;, d =&gt; y(d))
          .selectAll(function() { return [this, this.previousSibling]; })
          .clone(true)
            .attr(&quot;fill&quot;, &quot;currentColor&quot;)
            .attr(&quot;stroke&quot;, &quot;none&quot;)));

      const line = d3.lineRadial()
                    .curve(d3.curveLinearClosed)
                    .angle(d =&gt; x(d.minuteTime));

      const area = d3.areaRadial()
                    .curve(d3.curveLinearClosed)
                    .angle(d =&gt; x(d.minuteTime))

      const svg = d3.create(&quot;svg&quot;)
        .attr(&quot;viewBox&quot;, [-width / 2, -height / 2, width, height])
        .attr(&quot;stroke-linejoin&quot;, &quot;round&quot;)
        .attr(&quot;stroke-linecap&quot;, &quot;round&quot;);

svg.append(&quot;path&quot;)
  .attr(&quot;fill&quot;, &quot;none&quot;)
  .attr(&quot;stroke&quot;, &quot;red&quot;)
  .attr(&quot;stroke-width&quot;, 3)
  .attr(&quot;d&quot;, line
    .radius(d =&gt; y(d.VALUE1))
    (rawdata2));

svg.append(&quot;path&quot;)
  .attr(&quot;fill&quot;, &quot;none&quot;)
  .attr(&quot;stroke&quot;, &quot;green&quot;)
  .attr(&quot;stroke-width&quot;, 3)
  .attr(&quot;d&quot;, line
    .radius(d =&gt; y(d.VALUE2))
    (rawdata2));

svg.append(&quot;path&quot;)
  .attr(&quot;fill&quot;, function(_, i) {
    const d = rawdata2[i];
    console.log(d.VALUE1);
    if (d &amp;&amp; d.VALUE1 &gt; d.VALUE2) {
      return &quot;blue&quot;;
    } else {
      return &quot;gray&quot;;
    }
  })
  .attr(&quot;stroke&quot;, &quot;none&quot;)
  .attr(&quot;d&quot;, area
    .innerRadius(d =&gt; y(d.VALUE1))
    .outerRadius(d =&gt; y(d.VALUE2))
    (rawdata2));


      svg.append(&quot;g&quot;)
        .call(xAxis);

      svg.append(&quot;g&quot;)
        .call(yAxis);

      const container = d3.select(&quot;body&quot;).append(&quot;div&quot;);
      container.node().appendChild(svg.node());
    });

  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

How can I fix this? My expectation is to see blue area color from beginning of label 0 to until middle of label 4 and label 5. How can I achieve this? I want to fill the area in blue where the value of VALUE1 is greater than the value of VALUE2, and in gray where the value of VALUE2 is greater than the value of VALUE1.

EDIT: Based on answer of @pernifloss, I changed conditional filling by defininig two areas as following:

const positiveData = rawdata2.filter(d =&gt; d.VALUE1 &gt; d.VALUE2);
const negativeData = rawdata2.filter(d =&gt; d.VALUE2 &gt; d.VALUE1);
svg.selectAll(&quot;.positive-area&quot;)
.data([positiveData])
.enter()
.append(&quot;path&quot;)
.attr(&quot;class&quot;, &quot;positive-area&quot;)
.attr(&quot;fill&quot;, &quot;blue&quot;)
.attr(&quot;stroke&quot;, &quot;none&quot;)
.attr(&quot;d&quot;, area
.innerRadius(d =&gt; y(d.VALUE1))
.outerRadius(d =&gt; y(d.VALUE2))
);
svg.selectAll(&quot;.negative-area&quot;)
.data([negativeData])
.enter()
.append(&quot;path&quot;)
.attr(&quot;class&quot;, &quot;negative-area&quot;)
.attr(&quot;fill&quot;, &quot;gray&quot;)
.attr(&quot;stroke&quot;, &quot;none&quot;)
.attr(&quot;d&quot;, area
.innerRadius(d =&gt; y(d.VALUE1))
.outerRadius(d =&gt; y(d.VALUE2))
);

However, I ended up with this plot. 如何在D3中应用条件填充?

How can I make apply conditional filling, while keeping circular shape and circular areas? I do not want to have rectangular like areas.

答案1

得分: 1

你不能真正拥有一条带有多种颜色的路径。

我唯一看到的解决方法是创建多个区域。

将数据分为多组连续的“正”或“负”区域,然后为每个数据集绘制一个区域。

[编辑] 这是迄今为止我的代码,结果在https://imgur.com/FH6Xim7...

// 将数据分为正值和负值
let separated = rawdata2.reduce((a, b, index) => {
let sub = b.VALUE1 - b.VALUE2;
if (sub > 0) {
return { positive: [...a.positive, { ...b, index }], negative: [...a.negative] };
}
return { positive: [...a.positive], negative: [...a.negative, { ...b, index }] };
}, { positive: [], negative: [] })
const positiveSets = [];
let previous = undefined
separated.positive.forEach((e) => {
// 如果不连续
if (!previous || previous.index + 1 !== e.index) {
// 创建一个新的集合
positiveSets.push([e]);
} else {
// 将值附加到前一个集合
positiveSets[positiveSets.length - 1] = [...positiveSets[positiveSets.length - 1], e]
}
previous = e;
})
// 负值同样如此
const negativeSets = [];
previous = undefined
separated.negative.forEach((e) => {
if (!previous || previous.index + 1 !== e.index) {
negativeSets.push([e]);
} else {
negativeSets[negativeSets.length - 1] = [...negativeSets[negativeSets.length - 1], e]
}
previous = e;
})

我的区域函数:

const area = d3.areaRadial()
.curve(d3.curveLinear)
.angle(d => x(d.minuteTime))

然后将所有区域附加到图形:

const posG = svg.selectAll('.positive').data(positiveSets)
posG.enter().append('path')
.attr('class', 'positive')
.attr('fill', 'blue') // "positive" 颜色
.attr("d", (d) => area
.innerRadius(d => y(d.VALUE1))
.outerRadius(d => y(d.VALUE2))
(d));

const negG = svg.selectAll('.negative').data(negativeSets)
negG.enter().append('path')
.attr('class', 'negative') // "negative" 颜色
.attr('fill', 'red')
.attr("d", (d) => area
.innerRadius(d => y(d.VALUE1))
.outerRadius(d => y(d.VALUE2))
(d));

英文:

You can't really have one path with multiple colors.

The only solution I see is to make multiple areas.

Separate your data in multiple set of contiguous “positive” or “negative” area. Then draw an area for each dataset.

[edit] here is my code so far, the result https://imgur.com/FH6Xim7 ...

// separate data in positive and negative value
let separated = rawdata2.reduce((a, b,index) =&gt; {
let sub = b.VALUE1 - b.VALUE2;
if (sub &gt; 0) {
return {positive: [...a.positive, {...b,index}], negative: [...a.negative]};
}
return {positive: [...a.positive], negative: [...a.negative, {...b,index}]};
}, {positive: [], negative: []})
const positiveSets = [];
let previous = undefined
separated.positive.forEach((e)=&gt;{
//if not contiguous
if (!previous || previous.index + 1 !== e.index) {
// create a new set
positiveSets.push([e]);
} else {
// append value to previous set
positiveSets[positiveSets.length - 1] = [...positiveSets[positiveSets.length - 1], e]
}
previous = e;
})
//same for negatives
const negativeSets = [];
previous = undefined
separated.negative.forEach((e)=&gt;{
if (!previous || previous.index + 1 !== e.index) {
negativeSets.push([e]);
} else {
negativeSets[negativeSets.length - 1] = [...negativeSets[negativeSets.length - 1], e]
}
previous = e;
})

My area function:

const area = d3.areaRadial()
.curve(d3.curveLinear)
.angle(d =&gt; x(d.minuteTime))

en then append all area to graph :

const posG = svg.selectAll(&#39;.positive&#39;).data(positiveSets)
posG.enter().append(&#39;path&#39;)
.attr(&#39;class&#39;,&#39;positive&#39;)
.attr(&#39;fill&#39;,&#39;blue&#39;) // &quot;positive&quot; color
.attr(&quot;d&quot;, (d)=&gt;area
.innerRadius(d =&gt; y(d.VALUE1))
.outerRadius(d =&gt; y(d.VALUE2))
(d));
const negG = svg.selectAll(&#39;.negative&#39;).data(negativeSets)
negG.enter().append(&#39;path&#39;)
.attr(&#39;class&#39;,&#39;negative&#39;) // &quot;negative&quot; color
.attr(&#39;fill&#39;,&#39;red&#39;)
.attr(&quot;d&quot;, (d)=&gt;area
.innerRadius(d =&gt; y(d.VALUE1))
.outerRadius(d =&gt; y(d.VALUE2))
(d));

huangapple
  • 本文由 发表于 2023年7月12日 23:20:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76672153.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定