如何通过 D3 防止散点图上的点之间重叠并确保点保留在图表内?

How to prevent overlapping between dots on scatter plot via D3 and ensure that dots remain within chart?

提问人:Syed Usama Amer 提问时间:11/16/2023 更新时间:11/16/2023 访问量:25

问:

问题描述: 我正在 React 组件中使用 D3.js 构建散点图。我的目标是显示一组数据点(节点),而不会使它们相互重叠或溢出到图表边界之外。我正在使用 D3 的力模拟来实现这一点。但是,我遇到了两个问题:

  1. 这些节点相互重叠。
  2. 某些节点溢出到图表边界之外。

我的工作基于这个可观察的:https://observablehq.com/@keckelt/collision-free-scatter-plot

尝试的解决方案: 我使用 D3 的 forceSimulation 和 forceX、forceY 和 forceCollide 来定位节点并防止重叠。但是,这些节点仍然重叠,有些节点甚至溢出图表区域。

设置秤: 这是我设置比例的useEffect钩子:

useEffect(() => {
  const [widthAdjusted, heightAdjusted] = getAdjustedWidth(width, height);

  const scaleX = scaleLinear()
    .domain([Math.min(...data.map(d => d.x)), Math.max(...data.map(d => d.x))])
    .nice()
    .range([0, widthAdjusted]);

  const scaleY = scaleLinear()
    .domain([Math.min(...data.map(d => d.y)), Math.max(...data.map(d => d.y))])
    .nice()
    .range([heightAdjusted, 0]);

  setScales({ scaleX, scaleY });
}, [data, width, height]);

力模拟: 另一个 useEffect 钩子中的 D3 力模拟设置:

useEffect(() => {
  if (!scales) return;

  const transformedData = data.map(d => ({
    ...d,
    x: scales.scaleX(d.x),
    y: scales.scaleY(d.y),
  }));

  const forceSimulation = d3.forceSimulation(transformedData)
    .force('x', d3.forceX(d => d.x).strength(0.1))
    .force('y', d3.forceY(d => d.y).strength(0.1))
    .force('collide', d3.forceCollide().radius(20).strength(1))
    .stop();

  for (let i = 0; i < 4; i++) {
    forceSimulation.tick();
  }

  const updatedData = forceSimulation.nodes().map(d => ({
    ...d,
    x: scales.scaleX.invert(d.x),
    y: scales.scaleY.invert(d.y),
  }));

  setNodes(updatedData);
}, [data, scales]);

如何调整力模拟和缩放,以确保节点不会重叠并保持在图表边界内?

JavaScript ReactJS D3.js 冲突检测

评论


答: 暂无答案