我想根據我的資料集繪制一系列線。很難弄清楚出了什么問題,因為我沒有收到任何錯誤訊息。我希望比我更有經驗的人熟悉一些常見的陷阱。
這是對兩個示例的改編:使用 es6 classes和d3 multiline chart構建 d3 代碼
以下是相關部分(我認為事情出錯的地方):
createScales(){
this.keynames = d3.scaleOrdinal();
this.keynames.domain(Object.keys(this.data[0]).filter(key => key!=='date'));
this.keymap = this.keynames.domain().map(
keyname => ({name: keyname, values: this.data.map(
d => ({date: d.date, key: d[keyname]})
)})
);
const m = this.margin;
const xExtent = d3.extent(this.keymap, d => d.date);
const yExtent = [0,d3.max(this.keymap, d => Math.max(d.values, function(v){ return v.key }) )];
this.xScale = d3.scaleTime()
.range([0, this.width-m.right])
.domain(xExtent).nice();
this.yScale = d3.scaleLinear()
.range([this.height-(m.top m.bottom), 0])
.domain(yExtent).nice();
}
addAxes(){
const m = this.margin;
const xAxis = d3.axisBottom()
.scale(this.xScale)
.ticks(8);
const yAxis = d3.axisLeft()
.scale(this.yScale)
.ticks(4);
this.plot.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${this.height-(m.top m.bottom)})`)
.call(xAxis.ticks(8)); //more than 8 ticks shown
this.plot.append("g")
.attr("class", "y axis")
.call(yAxis.ticks(4)) //more than 4 ticks shown, rest of chain not working
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("$USD");
}
addLine(){
const line = d3.line()
.x(function(d){console.log(d); return this.xScale(d.date)}) //no log, no line
.y(function(d){return this.yScale(d.key)});
this.plot.append('path')
.datum(this.keymap)
.classed('line', true)
.attr('d', function(d){return line(d.values)}) //logs correct values, no line(data structure outlined below(1))
.style('stroke', this.lineColor || 'red')
.style('fill', 'none');
}
(1) 此控制臺日志中顯示的資料示例:
Array(4):
0: {name: aapl, values: Array(691)}
values: [0 .. 99]:
0: {date: Monday etc.., key: 38}
1: {date: Tuesday etc.., key: 39}
2: {date: Wednesday etc.., key: 38} ... etc
1: {name: tsla, values: Array(691)}
etc.
我看不出問題出在哪里.. 我的資料結構與示例中的完全相同,而且我之前的無類實作效果很好.. 未顯示的軸元素只是上面的櫻桃蛋糕,但也許他們指出了一個更大的問題。謝謝你。
完整代碼和資料:檔案1:plot.js
const chart = new Chart({element: document.querySelector('#graph')});
let getData = d3.csv('d1.csv', function(d){
function removeNaN(e,c){
if (e>0) {return e} else {return c}
}
return { date: d3.timeParse("%Y-%m-%d")(d.Date),
aapl : d.AAPL, tsla : d.TSLA,
aapl_sma: removeNaN( d.SMA_AAPL,d.AAPL),
tsla_sma: removeNaN( d.SMA_TSLA,d.TSLA)
}
}).then(init);
function init(data){
chart.setData(data);
}
檔案 2:chart.js
class Chart{
constructor(opts){
this.data = opts.data;
this.element = opts.element;
}
draw(){
this.width = this.element.offsetWidth;
this.height = this.width/2;
this.padding = 50;
this.margin = {
top : 20,
bottom : 20,
left : 30,
right : 50
};
this.element.innerHTML = '';
const svg = d3.select(this.element).append('svg');
svg.attr('width', this.width);
svg.attr('height', this.height);
this.plot = svg.append('g')
.attr('transform', `translate(${this.margin.left},${this.margin.top})`);
this.createScales();
this.addAxes();
this.addLine();
}
createScales(){
this.keynames = d3.scaleOrdinal();
this.keynames.domain(Object.keys(this.data[0]).filter(key => key!=='date'));
this.keymap = this.keynames.domain().map(
keyname => ({name: keyname, values: this.data.map(
d => ({date: d.date, key: d[keyname]})
)})
);
const m = this.margin;
const xExtent = d3.extent(this.data, d => d.date);
const yExtent = [0,d3.max(this.keymap, d => d3.max(d.values, function(v){ return v.key }) )];
this.xScale = d3.scaleTime()
.range([0, this.width-m.right])
.domain(xExtent).nice();
this.yScale = d3.scaleLinear()
.range([this.height-(m.top m.bottom), 0])
.domain(yExtent).nice();
}
addAxes(){
const m = this.margin;
const xAxis = d3.axisBottom()
.scale(this.xScale);
const yAxis = d3.axisLeft()
.scale(this.yScale);
this.plot.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${this.height-(m.top m.bottom)})`)
.call(xAxis.ticks(8));
this.plot.append("g")
.attr("class", "y axis")
.call(yAxis.ticks(4))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("$USD");
}
addLine(){
const line = d3.line()
.x(function(d){console.log(d); return this.xScale(d.date)})
.y(function(d){return this.yScale(d.key)});
this.plot.append('path')
.datum(this.keymap)
.classed('line', true)
.attr('d', function(d){console.log(d); return line(d.values)})
.style('stroke', this.lineColor || 'red')
.style('fill', 'none');
console.log(this.plot)
}
setColor(newColor){
this.plot.select('.line')
.style('stroke', newColor);
this.lineColor = newColor;
}
setData(data){
this.data = data;
this.draw();
}
}
檔案 3:index.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Graphs of the US Economy</title>
<link href="https://fonts.googleapis.com/css2?family=Source Sans Pro:wght@200;400;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<style>
</style>
</head>
<body>
<div id="container" >
<div id='graph'></div>
<div id="sections">
<div><h1>THIS IS A TEST SECTION THAT I'M USING TO FIGURE OUT HOW MY CODE WORKS</h1></div>
<div><h1>THIS IS A SECOND TEST SECTION THAT I'M USING TO FIGURE OUT HOW MY CODE WORKS</h1></div>
<div><h1>THIS IS A THIRD TEST SECTION THAT I'M USING TO FIGURE OUT HOW MY CODE WORKS</h1></div>
<div><h1>THIS IS A FOURTH TEST SECTION THAT I'M USING TO FIGURE OUT HOW MY CODE WORKS</h1></div>
<div><h1>THIS IS A FIFTH TEST SECTION THAT I'M USING TO FIGURE OUT HOW MY CODE WORKS</h1></div>
<div><h1>THIS IS A SIXTH TEST SECTION THAT I'M USING TO FIGURE OUT HOW MY CODE WORKS</h1></div>
</div>
</div>
<script src="https://d3js.org/d3.v6.js"></script>
<script src="graph-scroll.js"></script>
<script src="chart.js"></script>
<script src="plot.js"></script>
<script>
</script>
</body>
</html>
檔案 4:d1.csv,39 行:
Date,AAPL,SMA_AAPL,TSLA,SMA_TSLA
2018-12-31,38.33848571777344,,66.55999755859375,
2019-01-02,38.382225036621094,,62.02399826049805,
2019-01-03,34.55907440185547,,60.071998596191406,
2019-01-04,36.03437805175781,,63.53799819946289,
2019-01-07,35.95417022705078,,66.99199676513672,
2019-01-08,36.63956832885742,,67.06999969482422,
2019-01-09,37.26177215576172,,67.70600128173828,
2019-01-10,37.380863189697266,,68.99400329589844,
2019-01-11,37.013858795166016,,69.4520034790039,
2019-01-14,36.4572868347168,,66.87999725341797,
2019-01-15,37.20343780517578,,68.88600158691406,
2019-01-16,37.657936096191406,,69.20999908447266,
2019-01-17,37.88154602050781,,69.46199798583984,
2019-01-18,38.11487579345703,,60.45199966430664,
2019-01-22,37.259342193603516,,59.784000396728516,
2019-01-23,37.410030364990234,,57.518001556396484,
2019-01-24,37.113521575927734,,58.301998138427734,
2019-01-25,38.34333801269531,,59.40800094604492,
2019-01-28,37.988487243652344,,59.2760009765625,
2019-01-29,37.59474182128906,,59.492000579833984,
2019-01-30,40.16377258300781,,61.75400161743164,
2019-01-31,40.453006744384766,,61.40399932861328,
2019-02-01,40.472450256347656,,62.44200134277344,
2019-02-04,41.622066497802734,,62.577999114990234,
2019-02-05,42.33420181274414,,64.2699966430664,
2019-02-06,42.34878158569336,,63.444000244140625,
2019-02-07,41.546722412109375,,61.50199890136719,
2019-02-08,41.59553909301758,,61.15999984741211,
2019-02-11,41.35633087158203,,62.56800079345703,
2019-02-12,41.71269989013672,38.606483713785806,62.36199951171875,63.48539975484212
2019-02-13,41.539398193359375,38.71318079630534,61.63399887084961,63.32119979858398
2019-02-14,41.69073486328125,38.823464457194014,60.75400161743164,63.278866577148435
2019-02-15,41.59797286987305,39.05809440612793,61.57600021362305,63.32899996439616
2019-02-19,41.72246551513672,39.247697321573895,61.12799835205078,63.24866663614909
2019-02-20,41.990962982177734,39.44892374674479,60.512001037597656,63.032666778564455
2019-02-21,41.75419616699219,39.619411341349284,58.24599838256836,62.738533401489256
2019-02-22,42.22041702270508,39.78469950358073,58.94200134277344,62.44640007019043
2019-02-25,42.5279655456543,39.95626958211263,59.75400161743164,62.13840001424153
uj5u.com熱心網友回復:
主要問題出在addLine方法上。首先,嘗試將 a 添加console.log(this)到您傳遞給的函式.x():
const line = d3.line()
.x(function(d){console.log('this:', this); return this.xScale(d.date)})
.y(function(d){return this.yScale(d.key)});
您將在此函式中看到thisis undefined,因此您無法訪問this.xScale. 這是由于函式內部的this行為。
考慮這個例子:
class Example {
constructor(x) {
this.x = x;
}
print() {
console.log('in print method:', this);
function normal() {
console.log('in normal function:', this);
}
const arrow = () => console.log('in arrow function:', this);
normal();
arrow();
}
}
const ex = new Example(4);
ex.print();
this在普通函式中未定義,但在箭頭函式中,this指的是物件。因此,我們可以調整線生成器以使用箭頭函式:
const line = d3.line()
.x(d => this.xScale(d.date))
.y(d => this.yScale(d.key));
其次,您想為 中的每個元素繪制一條線this.keymap,因此您需要進行資料連接:
this.plot.append('g')
.selectAll('path')
.data(this.keymap)
.join('path')
.classed('line', true)
.attr('d', function (d) { return line(d.values) })
.style('stroke', this.lineColor || 'red')
.style('fill', 'none');
這是一個完整的例子。我已經改變了資料傳遞到圖表的方式,以便我可以把它全部放在一個片段中。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://d3js.org/d3.v7.js"></script>
</head>
<body>
<div id="graph"></div>
<script>
class Chart {
constructor(opts) {
this.data = opts.data;
this.element = opts.element;
}
draw() {
this.width = this.element.offsetWidth;
this.height = this.width / 2;
this.padding = 50;
this.margin = {
top: 20,
bottom: 20,
left: 30,
right: 50
};
this.element.innerHTML = '';
const svg = d3.select(this.element).append('svg');
svg.attr('width', this.width);
svg.attr('height', this.height);
this.plot = svg.append('g')
.attr('transform', `translate(${this.margin.left},${this.margin.top})`);
this.createScales();
this.addAxes();
this.addLine();
}
createScales() {
this.keynames = d3.scaleOrdinal();
this.keynames.domain(Object.keys(this.data[0]).filter(key => key !== 'date'));
this.keymap = this.keynames.domain().map(
keyname => ({
name: keyname, values: this.data.map(
d => ({ date: d.date, key: d[keyname] })
)
})
);
const m = this.margin;
const xExtent = d3.extent(this.data, d => d.date);
const yExtent = [0, d3.max(this.keymap, d => d3.max(d.values, function (v) { return v.key }))];
this.xScale = d3.scaleTime()
.range([0, this.width - m.right])
.domain(xExtent).nice();
this.yScale = d3.scaleLinear()
.range([this.height - (m.top m.bottom), 0])
.domain(yExtent).nice();
}
addAxes() {
const m = this.margin;
const xAxis = d3.axisBottom()
.scale(this.xScale);
const yAxis = d3.axisLeft()
.scale(this.yScale);
this.plot.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${this.height - (m.top m.bottom)})`)
.call(xAxis.ticks(8));
this.plot.append("g")
.attr("class", "y axis")
.call(yAxis.ticks(4))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.attr("fill", "black")
.style("text-anchor", "end")
.text("$USD");
}
addLine() {
const line = d3.line()
.x(d => this.xScale(d.date))
.y(d => this.yScale(d.key));
this.plot.append('g')
.selectAll('path')
.data(this.keymap)
.join('path')
.classed('line', true)
.attr('d', function (d) { return line(d.values) })
.style('stroke', this.lineColor || 'red')
.style('fill', 'none');
}
setColor(newColor) {
this.plot.select('.line')
.style('stroke', newColor);
this.lineColor = newColor;
}
setData(data) {
this.data = data;
this.draw();
}
}
const chart = new Chart({ element: document.querySelector('#graph') });
const data = d3.csvParse(`Date,AAPL,SMA_AAPL,TSLA,SMA_TSLA
2018-12-31,38.33848571777344,,66.55999755859375,
2019-01-02,38.382225036621094,,62.02399826049805,
2019-01-03,34.55907440185547,,60.071998596191406,
2019-01-04,36.03437805175781,,63.53799819946289,
2019-01-07,35.95417022705078,,66.99199676513672,
2019-01-08,36.63956832885742,,67.06999969482422,
2019-01-09,37.26177215576172,,67.70600128173828,
2019-01-10,37.380863189697266,,68.99400329589844,
2019-01-11,37.013858795166016,,69.4520034790039,
2019-01-14,36.4572868347168,,66.87999725341797,
2019-01-15,37.20343780517578,,68.88600158691406,
2019-01-16,37.657936096191406,,69.20999908447266,
2019-01-17,37.88154602050781,,69.46199798583984,
2019-01-18,38.11487579345703,,60.45199966430664,
2019-01-22,37.259342193603516,,59.784000396728516,
2019-01-23,37.410030364990234,,57.518001556396484,
2019-01-24,37.113521575927734,,58.301998138427734,
2019-01-25,38.34333801269531,,59.40800094604492,
2019-01-28,37.988487243652344,,59.2760009765625,
2019-01-29,37.59474182128906,,59.492000579833984,
2019-01-30,40.16377258300781,,61.75400161743164,
2019-01-31,40.453006744384766,,61.40399932861328,
2019-02-01,40.472450256347656,,62.44200134277344,
2019-02-04,41.622066497802734,,62.577999114990234,
2019-02-05,42.33420181274414,,64.2699966430664,
2019-02-06,42.34878158569336,,63.444000244140625,
2019-02-07,41.546722412109375,,61.50199890136719,
2019-02-08,41.59553909301758,,61.15999984741211,
2019-02-11,41.35633087158203,,62.56800079345703,
2019-02-12,41.71269989013672,38.606483713785806,62.36199951171875,63.48539975484212
2019-02-13,41.539398193359375,38.71318079630534,61.63399887084961,63.32119979858398
2019-02-14,41.69073486328125,38.823464457194014,60.75400161743164,63.278866577148435
2019-02-15,41.59797286987305,39.05809440612793,61.57600021362305,63.32899996439616
2019-02-19,41.72246551513672,39.247697321573895,61.12799835205078,63.24866663614909
2019-02-20,41.990962982177734,39.44892374674479,60.512001037597656,63.032666778564455
2019-02-21,41.75419616699219,39.619411341349284,58.24599838256836,62.738533401489256
2019-02-22,42.22041702270508,39.78469950358073,58.94200134277344,62.44640007019043
2019-02-25,42.5279655456543,39.95626958211263,59.75400161743164,62.13840001424153`, function (d) {
function removeNaN(e, c) {
if (e > 0) { return e; } else { return c; }
}
return {
date: d3.timeParse("%Y-%m-%d")(d.Date),
aapl: d.AAPL,
tsla: d.TSLA,
aapl_sma: removeNaN( d.SMA_AAPL, d.AAPL),
tsla_sma: removeNaN( d.SMA_TSLA, d.TSLA)
};
});
chart.setData(data);
</script>
</body>
</html>
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/325994.html
標籤:javascript d3.js
