如何在 d3 折线图中显示多条线?
Posted
技术标签:
【中文标题】如何在 d3 折线图中显示多条线?【英文标题】:How to show multiple lines in a d3 line graph? 【发布时间】:2020-12-23 23:22:24 【问题描述】:我希望在 d3 折线图中绘制多条线,并使用动画过渡每条线。这是一个工作示例,但一次显示 1 行。
https://www.d3-graph-gallery.com/graph/line_change_data.html
我正在尝试扩展它以同时显示多行。然后当点击 Dataset 2 按钮时,它会显示一组新的线条,并转换每一个线条。我的尝试是here
// Create 2 datasets
var data1 = [
[
ser1: 0.3,
ser2: 4
,
ser1: 2,
ser2: 16
,
ser1: 3,
ser2: 8
],
[
ser1: 1,
ser2: 7
,
ser1: 4,
ser2: 1
,
ser1: 6,
ser2: 8
]
];
var data2 = [
[
ser1: 4,
ser2: 7
,
ser1: 2,
ser2: 5
,
ser1: 2,
ser2: 3
],
[
ser1: 1,
ser2: 10
,
ser1: 5,
ser2: 8
,
ser1: 7,
ser2: 3
]
];
// set the dimensions and margins of the graph
var margin =
top: 10,
right: 30,
bottom: 30,
left: 50
,
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Initialise a X axis:
var x = d3.scaleLinear().range([0, width]);
var xAxis = d3.axisBottom().scale(x);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.attr("class", "myXaxis")
// Initialize an Y axis
var y = d3.scaleLinear().range([height, 0]);
var yAxis = d3.axisLeft().scale(y);
svg.append("g")
.attr("class", "myYaxis")
// Create a function that takes a dataset as input and update the plot:
function update(data)
// Create the X axis:
x.domain([0, d3.max(data, function(d)
return d3.max(d, function(d)
return d.ser1;
);
)]);
svg.selectAll(".myXaxis").transition()
.duration(3000)
.call(xAxis);
// create the Y axis
y.domain([0, d3.max(data, function(d)
return d3.max(d, function(d)
return d.ser2;
);
)]);
svg.selectAll(".myYaxis")
.transition()
.duration(3000)
.call(yAxis);
data.forEach(function(data, i)
// Create a update selection: bind to the new data
var u = svg.selectAll(`.lineTest$i`)
.data([data], function(d)
return d.ser1
);
// Update the line
u
.enter()
.append("path")
.attr("class", `.lineTest$i`)
.merge(u)
.transition()
.duration(3000)
.attr("d", d3.line()
.x(function(d)
return x(d.ser1);
)
.y(function(d)
return y(d.ser2);
))
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 2.5);
);
// At the beginning, I run the update function on the first dataset:
update(data1);
<script src="https://d3js.org/d3.v5.min.js"></script>
<!-- Add 2 buttons -->
<button onclick="update(data1)">Dataset 1</button>
<button onclick="update(data2)">Dataset 2</button>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
但问题是,当我单击数据集 2 按钮时,它会绘制新线,旧线仍然显示,并且它们之间没有过渡。
有人知道这里出了什么问题吗?
谢谢
【问题讨论】:
我认为这是你想要的工作:jsfiddle.net/kqjcobah。不过有几件事:数据连接将负责递归,因此不需要forEach
。设置班级时,不要输入句点 - 仅在选择课程时输入句点。我也将 line 函数移到了一个变量中。希望有帮助!
【参考方案1】:
几点说明:
-
正如@Ryan Morton 所指出的,只需将整组行传递给 d3,它会处理其余部分。不需要
forEach
;
您使用了attr('class', '.lineTest')
,但这给了它一个以点开头的类。这使得无法使用d3.select('.lineTest')
进行选择。删除点修复了该问题;
由于您的键函数选择d.ser1
,但d
是一个对象数组,ser1
未定义。我将 key 函数更新为只使用索引。
// Create 2 datasets
var data1 = [
[
ser1: 0.3,
ser2: 4
,
ser1: 2,
ser2: 16
,
ser1: 3,
ser2: 8
],
[
ser1: 1,
ser2: 7
,
ser1: 4,
ser2: 1
,
ser1: 6,
ser2: 8
]
];
var data2 = [
[
ser1: 4,
ser2: 7
,
ser1: 2,
ser2: 5
,
ser1: 2,
ser2: 3
],
[
ser1: 1,
ser2: 10
,
ser1: 5,
ser2: 8
,
ser1: 7,
ser2: 3
]
];
// set the dimensions and margins of the graph
var margin =
top: 10,
right: 30,
bottom: 30,
left: 50
,
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Initialise a X axis:
var x = d3.scaleLinear().range([0, width]);
var xAxis = d3.axisBottom().scale(x);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.attr("class", "myXaxis")
// Initialize an Y axis
var y = d3.scaleLinear().range([height, 0]);
var yAxis = d3.axisLeft().scale(y);
svg.append("g")
.attr("class", "myYaxis")
// Create a function that takes a dataset as input and update the plot:
function update(data)
// Create the X axis:
x.domain([0, d3.max(data, function(d)
return d3.max(d, function(d)
return d.ser1;
);
)]);
svg.selectAll(".myXaxis").transition()
.duration(3000)
.call(xAxis);
// create the Y axis
y.domain([0, d3.max(data, function(d)
return d3.max(d, function(d)
return d.ser2;
);
)]);
svg.selectAll(".myYaxis")
.transition()
.duration(3000)
.call(yAxis);
// Create a update selection: bind to the new data
var lines = svg.selectAll(`.lineTest`)
.data(data, function(d, i)
return i;
);
lines.exit()
.remove();
// Update the line
lines.enter()
.append("path")
.attr("class", "lineTest")
.merge(lines)
.transition()
.duration(3000)
.attr("d", d3.line()
.x(function(d)
return x(d.ser1);
)
.y(function(d)
return y(d.ser2);
))
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 2.5);
// At the beginning, I run the update function on the first dataset:
update(data1);
<script src="https://d3js.org/d3.v5.min.js"></script>
<!-- Add 2 buttons -->
<button onclick="update(data1)">Dataset 1</button>
<button onclick="update(data2)">Dataset 2</button>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
【讨论】:
以上是关于如何在 d3 折线图中显示多条线?的主要内容,如果未能解决你的问题,请参考以下文章