我在一个名为salesData.csv
的csv文件中有以下数据:
let salesData = [
{
year : 2021,
sales : 171,
expenses : 64
},
{
year : 2020,
sales : 145,
expenses : 64
},
{
year : 2019,
sales : 147,
expenses : 64
},
{
year : 2018,
sales : 161,
expenses : 64
},
{
year : 2017,
sales : 171,
expenses : 64
},
{
year : 2016,
sales : 141,
expenses : 52
},
{
year : 2015,
sales : 115,
expenses : 52
},
{
year : 2014,
sales : 132,
expenses : 52
},
{
year : 2013,
sales : 146,
expenses : 52
}
]
我的目标是根据用户选择的“指标”(在本例中为sales
或expenses
)呈现折线图。
我可以用这些数据呈现一个条形图,但不能基于相同数据呈现一个折线图。
为什么折线图无法正确呈现?
提前感谢您的帮助!
下面是我的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sales Data</title>
<style type="text/css">
.line {
fill: none;
stroke: teal;
stroke-width: 2;
}
</style>
</head>
<body>
<div id="chart-area"></div>
<script type="text/javascript">
let margin = {top: 40, right: 40, bottom: 60, left: 60};
let width = 600 - margin.left - margin.right;
let height = 500 - margin.top - margin.bottom;
let svg = d3.select("#chart-area").append("svg")
.attr('viewBox', [0, 0, width + margin.left + margin.right, height + margin.top + margin.bottom] )
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
let padding = 30;
// Date parser
let parseDate = d3.timeParse("%Y");
// Creates scale functions
let xScale = d3.scaleTime()
.range([ 0, width ]);
let yScale = d3.scaleLinear()
.range([ height, 0 ]);
// Defines axes
let xAxis = d3.axisBottom()
.scale(xScale);
let yAxis = d3.axisLeft()
.scale(yScale);
let xAxisGroup = svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
let yAxisGroup = svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(0, 0)')
.call(yAxis);
let xAxisLabel = svg.append('text')
.attr('id', 'y-axis-label')
.attr('class', 'axis-label');
// Initialize data
loadSalesData();
// Data
let data;
// Load CSV file
function loadSalesData() {
d3.csv("salesData.csv", row => {
row.YEAR = parseDate(row.YEAR);
row.REVENUE = +row.REVENUE;
row.EXPENSES = +row.EXPENSES;
return row
}).then(csv => {
// Store csv data in global variable
data = csv;
// Draw the chart
renderChart();
});
}
// Renders the chart
function renderChart() {
console.table(data);
// Gets the user's selection from the drop-down menu
let metricType = d3.select('#metric-type').property('value');
console.log(metricType);
// Sorts the data based on the user's selected metric
data.sort(( a, b ) => b[metricType] - a[metricType]);
// Specifies the DOMAINS
xScale.domain([d3.min(data, function(d) {return d.year; }), d3.max(data, function(d) {return d.year; }) ]);
yScale.domain([0, d3.max(data, function(d) {return d[metricType]; }) ]);
let lineGenerator = d3.line()
.x(function (d) { return xScale(d.year); })
.y(function (d) { return yScale(d[metricType]); })
.curve(d3.curveMonotoneX)(data)
;
// Draws bar chart
let bars = svg.selectAll('.bar')
.data(data);
bars
.exit()
.remove()
bars
.enter()
.append('rect')
.attr('class', 'bar')
.merge(bars)
.transition()
.duration(800)
.attr('x', d => xScale(d.YEAR))
.attr('y', d => yScale(d[metricType]))
.attr('height', d => (height - yScale(d[metricType])))
.attr('width', 10);
// Draws line chart
let linePlot = svg.append('path');
linePlot
.datum(data)
.attr('class', 'line')
.attr('d', lineGenerator)
xAxisGroup
.transition()
.duration(1000)
.style('font-size', '15px')
.call(xAxis);
yAxisGroup
.transition()
.duration(1000)
.style('font-size', '15px')
.call(yAxis);
}
</script>
<script src="https://d3js.org/d3.v7.min.js"></script>
</body>
</html>
1条答案
按热度按时间8xiog9wr1#
问题在于排序。
这一点:
需要变成这样: