多系列折线图
Multiple series line chart
我正在尝试创建多折线图。我找到了 this question which seems to be doing similar to what I am trying to do, but the example doesn't seem to be complete as I cannot get it to run. Below is the most minimal example I could create to demonstrate what I am trying to do, however it is not working. It should create a line series chart with two series, one for open, one for close. I have tried to use the same principle as used in the HTML table example here。
我正在使用 d3 版本 5.
const data = [
{ date: "Wed, 14 Aug 2019 00:00:00 GMT", close: 2.92, open: 3.2 },
{ date: "Wed, 28 Aug 2019 00:00:00 GMT", close: 2.89, open: 2.99 },
{ date: "Fri, 30 Aug 2019 00:00:00 GMT", close: 2.88, open: 3.4 },
{ date: "Mon, 02 Sep 2019 00:00:00 GMT", close: 2.89, open: 3.5 },
];
const margin = { top: 20, right: 20, bottom: 30, left: 50 };
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
// set the ranges
const x = d3
.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, width]);
const y = d3
.scaleLinear()
.domain([0, 4])
.range([height, 0]);
const g = d3
.select("body")
.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})`);
const seriesNames = ["open", "close"]
// create array where each element is a dataset for a specific series
const transformedData = seriesNames.map(colName => data.map(row => ({ date: row.date, value: row[colName] })));
const valueline = d3
.line()
.x(d => x(d.date))
.y(d => y(d.value));
let series = g
.selectAll("path")
.data(seriesNames)
.enter()
.append("path") // create path for each series
.data(colName => transformedData[colName]) // bind series-specific dataset to path
.attr("d", valueline) // create line from series-specific dataset
.attr("stroke", "red")
.attr("fill", "none");
// Add the X Axis
g.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x));
// Add the Y Axis
g.append("g").call(d3.axisLeft(y));
两件事:首先,将数据数组直接传递给 data
方法:
let series = g
.selectAll("path")
.data(transformedData)
//etc...
其次,你有一个时间尺度。因此,使用日期,而不是字符串:
data.forEach(d => d.date = new Date(d.date));
这是您的代码,其中包含这两项更改:
const data = [{
date: "Wed, 14 Aug 2019 00:00:00 GMT",
close: 2.92,
open: 3.2
},
{
date: "Wed, 28 Aug 2019 00:00:00 GMT",
close: 2.89,
open: 2.99
},
{
date: "Fri, 30 Aug 2019 00:00:00 GMT",
close: 2.88,
open: 3.4
},
{
date: "Mon, 02 Sep 2019 00:00:00 GMT",
close: 2.89,
open: 3.5
},
];
data.forEach(d => d.date = new Date(d.date));
const margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
};
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
// set the ranges
const x = d3
.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, width]);
const y = d3
.scaleLinear()
.domain([0, 4])
.range([height, 0]);
const g = d3
.select("body")
.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})`);
const seriesNames = ["open", "close"]
// create array where each element is a dataset for a specific series
const transformedData = seriesNames.map(colName => data.map(row => ({
date: row.date,
value: row[colName]
})));
const valueline = d3
.line()
.x(d => x(d.date))
.y(d => y(d.value));
let series = g
.selectAll("path")
.data(transformedData)
.enter()
.append("path") // create path for each series
.attr("d", valueline) // create line from series-specific dataset
.attr("stroke", "red")
.attr("fill", "none");
// Add the X Axis
g.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x));
// Add the Y Axis
g.append("g").call(d3.axisLeft(y));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
我正在尝试创建多折线图。我找到了 this question which seems to be doing similar to what I am trying to do, but the example doesn't seem to be complete as I cannot get it to run. Below is the most minimal example I could create to demonstrate what I am trying to do, however it is not working. It should create a line series chart with two series, one for open, one for close. I have tried to use the same principle as used in the HTML table example here。 我正在使用 d3 版本 5.
const data = [
{ date: "Wed, 14 Aug 2019 00:00:00 GMT", close: 2.92, open: 3.2 },
{ date: "Wed, 28 Aug 2019 00:00:00 GMT", close: 2.89, open: 2.99 },
{ date: "Fri, 30 Aug 2019 00:00:00 GMT", close: 2.88, open: 3.4 },
{ date: "Mon, 02 Sep 2019 00:00:00 GMT", close: 2.89, open: 3.5 },
];
const margin = { top: 20, right: 20, bottom: 30, left: 50 };
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
// set the ranges
const x = d3
.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, width]);
const y = d3
.scaleLinear()
.domain([0, 4])
.range([height, 0]);
const g = d3
.select("body")
.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})`);
const seriesNames = ["open", "close"]
// create array where each element is a dataset for a specific series
const transformedData = seriesNames.map(colName => data.map(row => ({ date: row.date, value: row[colName] })));
const valueline = d3
.line()
.x(d => x(d.date))
.y(d => y(d.value));
let series = g
.selectAll("path")
.data(seriesNames)
.enter()
.append("path") // create path for each series
.data(colName => transformedData[colName]) // bind series-specific dataset to path
.attr("d", valueline) // create line from series-specific dataset
.attr("stroke", "red")
.attr("fill", "none");
// Add the X Axis
g.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x));
// Add the Y Axis
g.append("g").call(d3.axisLeft(y));
两件事:首先,将数据数组直接传递给 data
方法:
let series = g
.selectAll("path")
.data(transformedData)
//etc...
其次,你有一个时间尺度。因此,使用日期,而不是字符串:
data.forEach(d => d.date = new Date(d.date));
这是您的代码,其中包含这两项更改:
const data = [{
date: "Wed, 14 Aug 2019 00:00:00 GMT",
close: 2.92,
open: 3.2
},
{
date: "Wed, 28 Aug 2019 00:00:00 GMT",
close: 2.89,
open: 2.99
},
{
date: "Fri, 30 Aug 2019 00:00:00 GMT",
close: 2.88,
open: 3.4
},
{
date: "Mon, 02 Sep 2019 00:00:00 GMT",
close: 2.89,
open: 3.5
},
];
data.forEach(d => d.date = new Date(d.date));
const margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
};
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
// set the ranges
const x = d3
.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, width]);
const y = d3
.scaleLinear()
.domain([0, 4])
.range([height, 0]);
const g = d3
.select("body")
.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})`);
const seriesNames = ["open", "close"]
// create array where each element is a dataset for a specific series
const transformedData = seriesNames.map(colName => data.map(row => ({
date: row.date,
value: row[colName]
})));
const valueline = d3
.line()
.x(d => x(d.date))
.y(d => y(d.value));
let series = g
.selectAll("path")
.data(transformedData)
.enter()
.append("path") // create path for each series
.attr("d", valueline) // create line from series-specific dataset
.attr("stroke", "red")
.attr("fill", "none");
// Add the X Axis
g.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x));
// Add the Y Axis
g.append("g").call(d3.axisLeft(y));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>