You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3径向图:基于STATE分组的双数组条件填充实现

D3径向图分组绘制与条件填充适配方案

1. 数据分组处理

先按STATE字段拆分原始数据:

// 按STATE二进制值分组
const rawdata3 = rawdata.filter(d => d.STATE === 0);
const rawdata4 = rawdata.filter(d => d.STATE === 1);

2. 径向线绘制

分别绑定对应数据,设置四条线的样式:

// rawdata3的VALUE1(红线)
svg.append("path")
  .datum(rawdata3)
  .attr("fill", "none")
  .attr("stroke", "#ff3333")
  .attr("stroke-width", 2)
  .attr("d", d3.lineRadial()
    .angle((d, i) => i * (2 * Math.PI) / rawdata3.length)
    .radius(d => yScale(d.VALUE1)));

// rawdata3的VALUE2(蓝线)
svg.append("path")
  .datum(rawdata3)
  .attr("fill", "none")
  .attr("stroke", "#3333ff")
  .attr("stroke-width", 2)
  .attr("d", d3.lineRadial()
    .angle((d, i) => i * (2 * Math.PI) / rawdata3.length)
    .radius(d => yScale(d.VALUE2)));

// rawdata4的VALUE1(绿线)
svg.append("path")
  .datum(rawdata4)
  .attr("fill", "none")
  .attr("stroke", "#33cc33")
  .attr("stroke-width", 2)
  .attr("d", d3.lineRadial()
    .angle((d, i) => i * (2 * Math.PI) / rawdata4.length)
    .radius(d => yScale(d.VALUE1)));

// rawdata4的VALUE2(绿线)
svg.append("path")
  .datum(rawdata4)
  .attr("fill", "none")
  .attr("stroke", "#33cc33")
  .attr("stroke-width", 2)
  .attr("d", d3.lineRadial()
    .angle((d, i) => i * (2 * Math.PI) / rawdata4.length)
    .radius(d => yScale(d.VALUE2)));

注:若两组数据长度不一致,需统一角度计算基准(比如基于原始数据总长度),保证线条角度对齐。

3. 交叉点计算与条件填充

3.1 对齐角度数据

先整理每个角度下的对应数值(已转换为径向半径):

// 假设两组数据长度一致,遍历每个角度点
const fillData = rawdata3.map((d3Item, idx) => {
  const d4Item = rawdata4[idx];
  return {
    angle: idx * (2 * Math.PI) / rawdata3.length,
    greenVal1: yScale(d4Item.VALUE1),
    greenVal2: yScale(d4Item.VALUE2),
    redVal: yScale(d3Item.VALUE1),
    blueVal: yScale(d3Item.VALUE2)
  };
});

3.2 红-绿区域填充

按规则填充绿线与红线之间的区域:

const redGreenArea = d3.areaRadial()
  .angle(d => d.angle)
  .innerRadius(d => Math.min(d.greenVal1, d.redVal))
  .outerRadius(d => Math.max(d.greenVal1, d.redVal))
  .curve(d3.curveLinearClosed);

svg.append("path")
  .datum(fillData)
  .attr("fill", d => d.greenVal1 > d.redVal ? "#ffcccc" : "#cc0000")
  .attr("opacity", 0.5)
  .attr("d", redGreenArea);

3.3 蓝-绿区域填充

按规则填充绿线与蓝线之间的区域:

const blueGreenArea = d3.areaRadial()
  .angle(d => d.angle)
  .innerRadius(d => Math.min(d.greenVal2, d.blueVal))
  .outerRadius(d => Math.max(d.greenVal2, d.blueVal))
  .curve(d3.curveLinearClosed);

svg.append("path")
  .datum(fillData)
  .attr("fill", d => d.greenVal2 > d.blueVal ? "#ccccff" : "#0000cc")
  .attr("opacity", 0.5)
  .attr("d", blueGreenArea);

3.4 交叉点标注(可选)

计算并绘制绿线与红线、蓝线的交叉点:

// 红-绿交叉点计算与绘制
const redGreenCrosses = fillData.filter((d, idx) => {
  const nextD = fillData[(idx + 1) % fillData.length];
  return (d.greenVal1 - d.redVal) * (nextD.greenVal1 - nextD.redVal) < 0;
});

svg.selectAll(".cross-red")
  .data(redGreenCrosses)
  .enter()
  .append("circle")
  .attr("class", "cross-red")
  .attr("cx", d => Math.cos(d.angle) * yScale((d.greenVal1 + d.redVal)/2) + centerX)
  .attr("cy", d => Math.sin(d.angle) * yScale((d.greenVal1 + d.redVal)/2) + centerY)
  .attr("r", 3)
  .attr("fill", "#ff0000");

// 蓝-绿交叉点计算与绘制
const blueGreenCrosses = fillData.filter((d, idx) => {
  const nextD = fillData[(idx + 1) % fillData.length];
  return (d.greenVal2 - d.blueVal) * (nextD.greenVal2 - nextD.blueVal) < 0;
});

svg.selectAll(".cross-blue")
  .data(blueGreenCrosses)
  .enter()
  .append("circle")
  .attr("class", "cross-blue")
  .attr("cx", d => Math.cos(d.angle) * yScale((d.greenVal2 + d.blueVal)/2) + centerX)
  .attr("cy", d => Math.sin(d.angle) * yScale((d.greenVal2 + d.blueVal)/2) + centerY)
  .attr("r", 3)
  .attr("fill", "#0000ff");

注:centerX和centerY为径向图的中心坐标,需根据画布尺寸定义。

内容的提问来源于stack exchange,提问作者dsapprentice

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 02:57:40