无法在多折线图d3上放置圆圈

问题描述

我尝试了很多方法来绑定数据,但是没有运气。

我的部分代码如下:

 let circleData = data.map((i) => i.values);
      mainGraph
        // .append("g")
        .selectAll("circle")
        .data(circleData)
        .enter()
        .append("circle")
        .attrs({
          cx: (d) => xScale(d.name),cy: (d) => yScale(d.value),r: 3,opacity: 1,});

我对数据功能很困惑,使用相同的方法画出了可以正常工作的线,但是当涉及到圆时,似乎根本无法读取数据。我希望有人能帮助我理解这一点,非常感谢!

const data = [{
  category: "series_1",values: [{
      name: "A",value: 10
    },{
      name: "B",value: 21
    },{
      name: "C",value: 19
    },{
      name: "D",value: 23
    },{
      name: "E",value: 20
    },],},];
let counter = 1;
const add_set = (arr) => {
  let copy = JSON.parse(JSON.stringify(arr[0]));
  const random = () => Math.floor(Math.random() * 20 + 1);
  const add = (arr) => {
    counter++;
    copy.values.map((i) => (i.value = random()));
    copy.category = `series_${counter}`;
    arr.push(copy);
  };
  add(arr);
};
add_set(data);

//No.1 define the svg
let graphWidth = 600,graphHeight = 300;
let margin = {
  top: 60,right: 10,bottom: 30,left: 45
};
let totalWidth = graphWidth + margin.left + margin.right,totalHeight = graphHeight + margin.top + margin.bottom;
let svg = d3
  .select("body")
  .append("svg")
  .attr("width",totalWidth)
  .attr("height",totalHeight);
//No.2 define mainGraph
let mainGraph = svg
  .append("g")
  .attr("transform","translate(" + margin.left + "," + margin.top + ")");
//No.3 define axises
let categoriesNames = data[0].values.map((d) => d.name);
let xScale = d3
  .scalePoint()
  .domain(categoriesNames)
  .range([0,graphWidth]); // scalepoint make the axis starts with value compared with scaleBand
let colorScale = d3.scaleOrdinal(d3.schemeCategory10);
colorScale.domain(data.map((d) => d.category));

let yScale = d3
  .scaleLinear()
  .range([graphHeight,0])
  .domain([
    d3.min(data,(i) => d3.min(i.values,(x) => x.value)),d3.max(data,(i) => d3.max(i.values,]); //* If an arrow function is simply returning a single line of code,you can omit the statement brackets and the return keyword

//No.4 set axises
mainGraph
  .append("g")
  .attr("class","x axis")
  .attr("transform","translate(0," + graphHeight + ")")
  .call(d3.axisBottom(xScale));
mainGraph.append("g").attr("class","y axis").call(d3.axisLeft(yScale));
//No.5 make lines
let lineGenerator = d3
  .line()
  .x((d) => xScale(d.name))
  .y((d) => yScale(d.value))
  .curve(d3.curveMonotoneX);

var lines = mainGraph
  .selectAll(".path")
  .data(data.map((i) => i.values))
  .enter()
  .append("path")
  .attr("d",lineGenerator)
  .attr("fill","none")
  .attr("stroke-width",3)
  .attr("stroke",(d,i) => colorScale(i));

//No.6 append circles
let circleData = data.map((i) => i.values);
mainGraph
  // .append("g")
  .selectAll("circle")
  .data(circleData)
  .enter()
  .append("circle")
  .attrs({
    cx: (d) => xScale(d.name),});
.line {
  stroke: blue;
  fill: none;
}
<script src="https://d3js.org/d3.v6.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>

解决方法

首先,您的问题是,对于一条线,您传递一个 array 数据点,但是对于一个圆,您传递了一个 single 数据点。简单地应用console.log(circleData)可以告诉我circleData是一个数组数组。


有多种方法可以使代码正常工作。一种是使用circleData.flat()将所有圆数据点展平为单个数组。好处是,这是迄今为止最简单的解决方案。缺点是您使用了(d,i) => colorScale(i),现在i变得一团糟。

//No.6 append circles
let circleData = data.map((i) => i.values).flat();
mainGraph
  .selectAll("circle")
  .data(circleData)
  .enter()
  .append("circle")
  .attrs({
    cx: (d) => xScale(d.name),cy: (d) => yScale(d.value),r: 3,opacity: 1,});

对于线,i对于线1变为0,对于线2变为1,以此类推。对于圆,我们希望它变为5的0和5的1,但是改为{{ 1}}。因为这就是计数器的作用,所以计数。

您可以通过添加一个属性来更改数据,该属性可以告诉您圆属于哪条线,或者您可以倾斜该属性并将依赖于一条线的所有圆放入单个0,1,2,...,10元素中。这意味着为每个线/圆组合附加一个g

它有一些好处。一个是g可以从该fill元素继承,因此您可以继续使用g。另一个是,您甚至可以将该行移到组中,从而为突出显示,显示/隐藏或执行其他操作提供了一种非常简单的方法。

colorScape(i)
const data = [{
  category: "series_1",values: [{
      name: "A",value: 10
    },{
      name: "B",value: 21
    },{
      name: "C",value: 19
    },{
      name: "D",value: 23
    },{
      name: "E",value: 20
    },],},];
let counter = 1;
const add_set = (arr) => {
  let copy = JSON.parse(JSON.stringify(arr[0]));
  const random = () => Math.floor(Math.random() * 20 + 1);
  const add = (arr) => {
    counter++;
    copy.values.map((i) => (i.value = random()));
    copy.category = `series_${counter}`;
    arr.push(copy);
  };
  add(arr);
};
add_set(data);

//No.1 define the svg
let graphWidth = 600,graphHeight = 300;
let margin = {
  top: 60,right: 10,bottom: 30,left: 45
};
let totalWidth = graphWidth + margin.left + margin.right,totalHeight = graphHeight + margin.top + margin.bottom;
let svg = d3
  .select("body")
  .append("svg")
  .attr("width",totalWidth)
  .attr("height",totalHeight);
//No.2 define mainGraph
let mainGraph = svg
  .append("g")
  .attr("transform","translate(" + margin.left + "," + margin.top + ")");
//No.3 define axises
let categoriesNames = data[0].values.map((d) => d.name);
let xScale = d3
  .scalePoint()
  .domain(categoriesNames)
  .range([0,graphWidth]); // scalepoint make the axis starts with value compared with scaleBand
let colorScale = d3.scaleOrdinal(d3.schemeCategory10);
colorScale.domain(data.map((d) => d.category));

let yScale = d3
  .scaleLinear()
  .range([graphHeight,0])
  .domain([
    d3.min(data,(i) => d3.min(i.values,(x) => x.value)),d3.max(data,(i) => d3.max(i.values,]); //* If an arrow function is simply returning a single line of code,you can omit the statement brackets and the return keyword

//No.4 set axises
mainGraph
  .append("g")
  .attr("class","x axis")
  .attr("transform","translate(0," + graphHeight + ")")
  .call(d3.axisBottom(xScale));
mainGraph.append("g").attr("class","y axis").call(d3.axisLeft(yScale));
//No.5 make lines
let lineGenerator = d3
  .line()
  .x((d) => xScale(d.name))
  .y((d) => yScale(d.value))
  .curve(d3.curveMonotoneX);

var lines = mainGraph
  .selectAll(".path")
  .data(data.map((i) => i.values))
  .enter()
  .append("path")
  .attr("d",lineGenerator)
  .attr("fill","none")
  .attr("stroke-width",3)
  .attr("stroke",(d,i) => colorScale(i));

//No.6 append circles
let circleData = data.map((i) => i.values);
mainGraph
  .selectAll(".circle-container")
  .data(circleData)
  .enter()
  .append("g")
  .attr("class","circle-container")
  .attr("fill",i) => console.log(d) || colorScale(i))
  .selectAll("circle")
  .data((d) => d)
  .enter()
  .append("circle")
  .attrs({
    cx: (d) => xScale(d.name),});
.line {
  stroke: blue;
  fill: none;
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...