TypeScript type confusion (TypeError: Cannot read property 'slice' of undefined)
TypeScript type confusion (TypeError: Cannot read property 'slice' of undefined)
我的 Angular 项目的 csv
文件中有以下数据,该项目还导入了 D3.js
库:
group,Nitrogen,normal,stress
banana,12,1,13
poacee,6,6,33
sorgho,11,28,12
triticum,19,6,1
我在打字稿文件中也有以下代码来显示堆叠条:
import { Component, OnInit } from '@angular/core';
import * as d3 from 'd3';
@Component({
selector: 'app-stacked-bar',
templateUrl: './stacked-bar.component.html',
styleUrls: ['./stacked-bar.component.css']
})
export class StackedBarComponent implements OnInit {
data = [
{"group": "banana", "Nitrogen": "12", "normal": "1", "stress": "13"},
{"group": "poacee", "Nitrogen": "6", "normal": "6", "stress": "33"},
{"group": "sorgho", "Nitrogen": "11", "normal": "28", "stress": "12"},
{"group": "triticum", "Nitrogen": "19", "normal": "6", "stress": "1"}
];
svg: any;
margin = 50;
width = 750 - (this.margin * 2);
height = 400 - (this.margin * 2);
ngOnInit(): void {
this.createSvg();
this.drawBars(this.data);
}
createSvg(): void {
this.svg = d3.select("figure#stacked-bar")
.append("svg")
.attr("width", this.width + (this.margin * 2))
.attr("height", this.height + (this.margin * 2))
.append("g")
.attr("transform", "translate(" + this.margin + "," + this.margin + ")");
}
drawBars(data): void {
// List of subgroups - Header of the csv file.
// ["Nitrogen", "normal", "stress"]
const subgroups = data.columns.slice(1);
// List of groups - Value of the first column, called group.
const groups = data.map(d => (d.group));
// Create the X-axis band scale.
const x = d3.scaleBand()
.domain(groups)
.range([0, this.width])
//.domain(data.map(d => d.groups))
.padding(0.2);
// Draw the X-axis on the DOM.
this.svg.append("g")
.attr("transform", "translate(0," + this.height + ")")
.call(d3.axisBottom(x).tickSizeOuter(0));
// Create the Y-axis band scale.
const y = d3.scaleLinear()
.domain([0, 60])
.range([this.height, 0]);
// Draw the Y-axis on the DOM.
this.svg.append("g")
.call(d3.axisLeft(y));
// color palette = one color per subgroup
const color = d3.scaleOrdinal()
.domain(subgroups)
.range(['#e41a1c','#377eb8','#4daf4a']);
// Stack the data per subgroup.
const stackedData = d3.stack()
.keys(subgroups)
(data);
// Create and fill the bars.
this.svg.append("g")
.selectAll("g")
.data(stackedData)
.join("g")
.attr("fill", d => color(d.key))
.selectAll("rect")
.data(d => d)
.join("rect")
.attr("x", d => x(d.data.group))
.attr("y", d => y(d[1]))
.attr("height", d => y(d[0]) - y(d[1]))
.attr("width", x.bandwidth());
}
}
但我只得到一个空图。当我检查页面时,出现此控制台错误:
TypeError: 无法读取未定义的 属性 'slice'
由于 data
中的某些类型歧义,无法应用 slice
方法,但是当我只是复制并粘贴 ["Nitrogen", "normal", "stress"]
代替代码中的 subgroups
时,一切正常!
有人可以帮我解决这个问题吗?
p.s。图表应该是这样的:
你能试试下面的代码吗?
const subgroups = data.columns?.slice(1) || [];
据我了解您的代码,您的数据对象中没有 属性 列。
您在文件开头定义了这样的数据:
data = [
{"group": "banana", "Nitrogen": "12", "normal": "1", "stress": "13"},
{"group": "poacee", "Nitrogen": "6", "normal": "6", "stress": "33"},
{"group": "sorgho", "Nitrogen": "11", "normal": "28", "stress": "12"},
{"group": "triticum", "Nitrogen": "19", "normal": "6", "stress": "1"}
];
所以我没有看到任何 属性 列。
并且数据已经是一个数组,所以我认为您应该这样做:
const subgroups = data.slice(1)
而且,顺便说一句,您似乎对 groups
变量做了正确的处理。
假设您正在从这个 example 开始工作,请注意这使用 d3.csv
将 csv 输入转换为对象数组。 D3 创建此数组 plus 自定义 columns
属性 示例中使用的
const csv = `group,Nitrogen,normal,stress
banana,12,1,13
poacee,6,6,33
sorgho,11,28,12
triticum,19,6,1`;
const data = d3.csvParse(csv);
console.log(data.columns);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
在您的代码中,您有相同的对象数组,但您没有显示 csv 导入方法,因此我们可以假设您没有使用 d3.csv
并使用其他一些方法来获取数据。
在这种情况下,data.columns
相当于 Object.keys(data[0])
。从那里你可以使用 slice
来获取你想要为堆栈分组的列:
const data = [
{"group": "banana", "Nitrogen": "12", "normal": "1", "stress": "13"},
{"group": "poacee", "Nitrogen": "6", "normal": "6", "stress": "33"},
{"group": "sorgho", "Nitrogen": "11", "normal": "28", "stress": "12"},
{"group": "triticum", "Nitrogen": "19", "normal": "6", "stress": "1"}
];
const dataColumns = Object.keys(data[0]);
console.log(dataColumns);
const subgroups = dataColumns.slice(1)
console.log(subgroups);
我现在无法自己测试,但我从 TypeScript 的编码中学到了很多类似的问题,通过将相关变量的类型设置为 'any' 解决了像这样:
const subgroups = (data as any).columns.slice(1)
由于我接触 Web 编程的时间很短,所以请对此持保留态度,所以我不能说这种方法是否会以某种方式对整体代码产生负面影响。欢迎对这个问题发表评论。
我的 Angular 项目的 csv
文件中有以下数据,该项目还导入了 D3.js
库:
group,Nitrogen,normal,stress
banana,12,1,13
poacee,6,6,33
sorgho,11,28,12
triticum,19,6,1
我在打字稿文件中也有以下代码来显示堆叠条:
import { Component, OnInit } from '@angular/core';
import * as d3 from 'd3';
@Component({
selector: 'app-stacked-bar',
templateUrl: './stacked-bar.component.html',
styleUrls: ['./stacked-bar.component.css']
})
export class StackedBarComponent implements OnInit {
data = [
{"group": "banana", "Nitrogen": "12", "normal": "1", "stress": "13"},
{"group": "poacee", "Nitrogen": "6", "normal": "6", "stress": "33"},
{"group": "sorgho", "Nitrogen": "11", "normal": "28", "stress": "12"},
{"group": "triticum", "Nitrogen": "19", "normal": "6", "stress": "1"}
];
svg: any;
margin = 50;
width = 750 - (this.margin * 2);
height = 400 - (this.margin * 2);
ngOnInit(): void {
this.createSvg();
this.drawBars(this.data);
}
createSvg(): void {
this.svg = d3.select("figure#stacked-bar")
.append("svg")
.attr("width", this.width + (this.margin * 2))
.attr("height", this.height + (this.margin * 2))
.append("g")
.attr("transform", "translate(" + this.margin + "," + this.margin + ")");
}
drawBars(data): void {
// List of subgroups - Header of the csv file.
// ["Nitrogen", "normal", "stress"]
const subgroups = data.columns.slice(1);
// List of groups - Value of the first column, called group.
const groups = data.map(d => (d.group));
// Create the X-axis band scale.
const x = d3.scaleBand()
.domain(groups)
.range([0, this.width])
//.domain(data.map(d => d.groups))
.padding(0.2);
// Draw the X-axis on the DOM.
this.svg.append("g")
.attr("transform", "translate(0," + this.height + ")")
.call(d3.axisBottom(x).tickSizeOuter(0));
// Create the Y-axis band scale.
const y = d3.scaleLinear()
.domain([0, 60])
.range([this.height, 0]);
// Draw the Y-axis on the DOM.
this.svg.append("g")
.call(d3.axisLeft(y));
// color palette = one color per subgroup
const color = d3.scaleOrdinal()
.domain(subgroups)
.range(['#e41a1c','#377eb8','#4daf4a']);
// Stack the data per subgroup.
const stackedData = d3.stack()
.keys(subgroups)
(data);
// Create and fill the bars.
this.svg.append("g")
.selectAll("g")
.data(stackedData)
.join("g")
.attr("fill", d => color(d.key))
.selectAll("rect")
.data(d => d)
.join("rect")
.attr("x", d => x(d.data.group))
.attr("y", d => y(d[1]))
.attr("height", d => y(d[0]) - y(d[1]))
.attr("width", x.bandwidth());
}
}
但我只得到一个空图。当我检查页面时,出现此控制台错误:
TypeError: 无法读取未定义的 属性 'slice'
由于 data
中的某些类型歧义,无法应用 slice
方法,但是当我只是复制并粘贴 ["Nitrogen", "normal", "stress"]
代替代码中的 subgroups
时,一切正常!
有人可以帮我解决这个问题吗?
p.s。图表应该是这样的:
你能试试下面的代码吗?
const subgroups = data.columns?.slice(1) || [];
据我了解您的代码,您的数据对象中没有 属性 列。
您在文件开头定义了这样的数据:
data = [
{"group": "banana", "Nitrogen": "12", "normal": "1", "stress": "13"},
{"group": "poacee", "Nitrogen": "6", "normal": "6", "stress": "33"},
{"group": "sorgho", "Nitrogen": "11", "normal": "28", "stress": "12"},
{"group": "triticum", "Nitrogen": "19", "normal": "6", "stress": "1"}
];
所以我没有看到任何 属性 列。
并且数据已经是一个数组,所以我认为您应该这样做:
const subgroups = data.slice(1)
而且,顺便说一句,您似乎对 groups
变量做了正确的处理。
假设您正在从这个 example 开始工作,请注意这使用 d3.csv
将 csv 输入转换为对象数组。 D3 创建此数组 plus 自定义 columns
属性 示例中使用的
const csv = `group,Nitrogen,normal,stress
banana,12,1,13
poacee,6,6,33
sorgho,11,28,12
triticum,19,6,1`;
const data = d3.csvParse(csv);
console.log(data.columns);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
在您的代码中,您有相同的对象数组,但您没有显示 csv 导入方法,因此我们可以假设您没有使用 d3.csv
并使用其他一些方法来获取数据。
在这种情况下,data.columns
相当于 Object.keys(data[0])
。从那里你可以使用 slice
来获取你想要为堆栈分组的列:
const data = [
{"group": "banana", "Nitrogen": "12", "normal": "1", "stress": "13"},
{"group": "poacee", "Nitrogen": "6", "normal": "6", "stress": "33"},
{"group": "sorgho", "Nitrogen": "11", "normal": "28", "stress": "12"},
{"group": "triticum", "Nitrogen": "19", "normal": "6", "stress": "1"}
];
const dataColumns = Object.keys(data[0]);
console.log(dataColumns);
const subgroups = dataColumns.slice(1)
console.log(subgroups);
我现在无法自己测试,但我从 TypeScript 的编码中学到了很多类似的问题,通过将相关变量的类型设置为 'any' 解决了像这样:
const subgroups = (data as any).columns.slice(1)
由于我接触 Web 编程的时间很短,所以请对此持保留态度,所以我不能说这种方法是否会以某种方式对整体代码产生负面影响。欢迎对这个问题发表评论。