-1

请参阅 Observablehq 笔记本中的代码:https ://observablehq.com/@erayalan/radial-scatter-plot

我试图了解如何更改这件作品中每个项目的大小和颜色:

data = [{ name : "foo", r: 40, theta: 1.4 }, 
        { name : "bar", r: 30, theta: 4.8 }, 
        { name : "baz", r: 60, theta: 3.05}] 
4

2 回答 2

0

要更改圆圈的大小,您可以使用该"r"属性,类似于使用“cx”和“cy”的方式。我假设您想将“theta”映射到大小。首先,您需要创建一个比例

  const radiusScale = d3.scaleLinear().domain(d3.extent(data, d=> d.theta)).range([10, 20])

函数extent ind3.extent(data, d=> d.theta)返回 theta 属性中数据的最大值和最小值(在本例中为[1.4, 4.8])。这意味着这个尺度有一个域[1.4, 4.8]和一个范围[10, 20],所以如果你调用radiusScale(1.4)它就会输出10,并且radiusScale(4.8)会输出20。有了这个,您将 theta 值映射到足够的半径,并可以将其用于"r"SVG 圆的属性:

  .attr("cx", d => d.r * Math.cos(d.theta))
  .attr("cy", d => d.r * Math.sin(d.theta))
  .attr("r", d => radiusScale(d.theta))

类似的逻辑适用于在"fill"属性中定义的颜色。您想将“foo”、“bar”和“baz”映射到不同的颜色。您可以scaleOrdinal为此使用和颜色数组:

   const colorScale = d3.scaleOrdinal().range(d3.schemeCategory10)

这个比例的范围是d3.schemeCategory10,它只是一个包含一些常见颜色的数组(您可以使用任何颜色数组)。您不需要此比例的域,因为 d3 可以自动为比例接收的每个唯一值分配不同的颜色。

然后您可以补充映射,将颜色分配给填充属性。

  .attr("cx", d => d.r * Math.cos(d.theta))
  .attr("cy", d => d.r * Math.sin(d.theta))
  .attr("r", d => radiusScale(d.theta))
  .attr("fill", d => colorScale(d.name))

这是您的笔记本的一个分支,其中包含上述更改:

旁注:

在我的回答中,我将 theta 的值直接映射到了半径。不推荐使用圆的半径来编码一个值,最好的做法是使用它的面积。为了简单起见,我不会在这里深入探讨,但您可以在此处查看更好的映射大小方法。

D3 的学习曲线可能有点陡峭。您在此答案中看到了几个更改颜色和大小的概念(比例、域、范围、范围等!)。您可能需要查看官方 d3 介绍,以更顺序的方式查看这些概念。

于 2021-04-21T19:10:11.440 回答
-1

这是一个包含大小和颜色的片段:

data = [
  {name: "foo", r: 40, theta: 1.4, size: 10, color: 'red'},
  {name: "bar", r: 30, theta: 4.8, size: 12, color: 'green'},
  {name: "baz", r: 60, theta: 3.05, size: 14, color: 'blue'}
];

const width = 200;
const height = 200;
const svg = d3.select('svg');

const radius = 100;
const r = d3.scaleLinear()
      .domain([0, 1])
      .range([0, radius]);

svg
  .attr("viewBox", `${-width / 2} ${-height / 2} ${width} ${height}`)
  .attr('width', width)
  .attr('height', height)
  .style("font", "10px sans-serif");

const gr = svg.append('g')
  .attr('class', 'r axis')
  .selectAll('g')
  .data(r.ticks(5).slice(1))
  .enter()
  .append('g');

gr.append('circle')
  .attr("fill", "none")
  .attr("stroke", "#ebebeb")
  .attr('r', r);

const ga = svg.append('g')
  .attr('class', 'a axis')
  .selectAll('g')
  .data(d3.range(0, 360, 30)) // line density
  .enter()
  .append('g')
  .attr('transform', d => 'rotate(' + -d + ')');

 ga.append('line')
   .attr("fill", "none")
   .attr("stroke", "#aaa")
   .attr('x2', radius);
  
 svg.selectAll("point") // No longer "rect"
  .data(data)
  .enter()
  .append("circle")
  .attr("cx", d => d.r * Math.cos(d.theta))
  .attr("cy", d => d.r * Math.sin(d.theta))
  .attr("r", d => d.size)
  .style('stroke', d => d.color)
  .style('fill', 'white');

  svg.selectAll("text") // Note "text", not "circle" or "rect"
  .data(data)
  .enter()
  .append("text")
  .text(d => d.name)
  .attr("x", d => d.r * Math.cos(d.theta))
  .attr("y", d => d.r * Math.sin(d.theta))
  .attr('alignment-baseline', 'middle')
  .attr('text-anchor', 'middle')
  .attr("font-family", "sans-serif")
  .attr("font-size", "11px")
  .attr("fill", d => d.color);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg/>

于 2021-04-21T19:22:12.907 回答