我正在使用D3js v5.12.0构建图表。
我已经完成了在X轴上具有变量year
和在Y轴上具有变量earth_footprint
的面积图。
数据在以下链接中:https://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/final_data_set.json
我希望在面积图的顶部绘制折线图。该折线图在X轴上应具有可变的Year,在Y轴上应具有pop_total。pop_total
是数据上的另一个变量。
但是我无法管理该方法,我看到了一些有关如何在条形图中画一条线的教程,但是当我适应作为面积图的代码时,它将不起作用。
提前致谢
的CSS
#area-chart {
text-align: center;
margin-top: 40px;
}
.selection {
fill: none;
}
HTLM
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="area-chart"></div>
</body>
</html>
JS
var url = "http://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/final_data_set.json";
d3.json(url)
.then(function(data) {
data = data.filter(dataPoint => dataPoint.country_code == 'BRA');
data = data.filter(element => element.hasOwnProperty("earth_footprint"));
const heightValue = 300;
const widthValue = 600;
// Create SVG and padding for the chart
const svg = d3
.select("#area-chart")
.append("svg")
.attr("viewBox", `0 0 ${widthValue} ${heightValue}`)
;
const strokeWidth = 1.5;
const margin = { top: 0, bottom: 20, left: 30, right: 20 };
const chart = svg.append("g").attr("transform", `translate(${margin.left},0)`);
const width = 600 - margin.left - margin.right - (strokeWidth * 2);
const height = 300 - margin.top - margin.bottom;
const grp = chart
.append("g")
.attr("transform", `translate(-${margin.left - strokeWidth},-${margin.top})`);
// Create scales
const yScale = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.earth_footprint)]);
const xScale = d3
.scaleLinear()
.range([0, width])
.domain(d3.extent(data, dataPoint => dataPoint.year));
const area = d3
.area()
.x(dataPoint => xScale(dataPoint.year))
.y0(height)
.y1(dataPoint => yScale(dataPoint.earth_footprint));
// Add area
grp
.append("path")
.attr("transform", `translate(${margin.left},0)`)
.datum(data)
.style("fill", "lightblue")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", strokeWidth)
.attr("d", area);
// Add the X Axis
chart
.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale).ticks(data.length));
// Add the Y Axis
chart
.append("g")
.attr("transform", `translate(0, 0)`)
.call(d3.axisLeft(yScale));
chart.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Number of Earths");
chart.append("text")
.attr("transform",
"translate(" + (width/2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Year");
});
最佳答案
为了显示该行,您需要一个行生成器:
const line = d3.area()
.x(dataPoint => xScale(dataPoint.year))
.y(dataPoint => yScale(dataPoint.pop_total));
但是,您的
yScale
将获得最大的earth_footprint
,并且pop_total
值将超出范围。因此,您将需要该线发生器的另一个比例尺:const yScale2 = d3.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.pop_total)]);
之后,只需添加路径:
grp.append("path")
.attr("d", line);
现在最大的问题是,您有两种视觉编码(面积和线条),它们的比例不同。因此,您需要为该线添加一个附加轴。我把那个工作留给你。
这是结果代码:
var url = "https://raw.githubusercontent.com/cvrnogueira/CODWorkData/master/database/final_data_set.json";
d3.json(url)
.then(function(data) {
data = data.filter(dataPoint => dataPoint.country_code == 'BRA');
data = data.filter(element => element.hasOwnProperty("earth_footprint"));
const heightValue = 300;
const widthValue = 600;
// Create SVG and padding for the chart
const svg = d3
.select("#area-chart")
.append("svg")
.attr("viewBox", `0 0 ${widthValue} ${heightValue}`);
const strokeWidth = 1.5;
const margin = {
top: 0,
bottom: 20,
left: 30,
right: 20
};
const chart = svg.append("g").attr("transform", `translate(${margin.left},0)`);
const width = 600 - margin.left - margin.right - (strokeWidth * 2);
const height = 300 - margin.top - margin.bottom;
const grp = chart
.append("g")
.attr("transform", `translate(-${margin.left - strokeWidth},-${margin.top})`);
// Create scales
const yScale = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.earth_footprint)]);
const yScale2 = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, dataPoint => dataPoint.pop_total)]);
const xScale = d3
.scaleLinear()
.range([0, width])
.domain(d3.extent(data, dataPoint => dataPoint.year));
const area = d3
.area()
.x(dataPoint => xScale(dataPoint.year))
.y0(height)
.y1(dataPoint => yScale(dataPoint.earth_footprint));
const line = d3.area()
.x(dataPoint => xScale(dataPoint.year))
.y(dataPoint => yScale2(dataPoint.pop_total));
// Add area
grp
.append("path")
.attr("transform", `translate(${margin.left},0)`)
.datum(data)
.style("fill", "lightblue")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", strokeWidth)
.attr("d", area);
grp
.append("path")
.attr("transform", `translate(${margin.left},0)`)
.datum(data)
.style("fill", "none")
.attr("stroke", "red")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", strokeWidth)
.attr("d", line);
// Add the X Axis
chart
.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale).ticks(data.length));
// Add the Y Axis
chart
.append("g")
.attr("transform", `translate(0, 0)`)
.call(d3.axisLeft(yScale));
chart.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Number of Earths");
chart.append("text")
.attr("transform",
"translate(" + (width / 2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Year");
});
#area-chart {
text-align: center;
margin-top: 40px;
}
.selection {
fill: none;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://d3js.org/d3.v5.min.js"></script>
<title>JS Bin</title>
</head>
<body>
<div id="area-chart"></div>
</body>
</html>
关于javascript - 在面积图上方绘制折线图,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58134349/