我正在使用d3图表创建堆积的条形图。我在前端有按钮。单击按钮时应显示图表。单击按钮时出现以下错误。
错误:属性y:预期长度为“ NaN”。
错误:属性高度:预期长度“ NaN”。
错误:属性宽度:预期长度为“ 10,900”。
import * as d3 from 'd3';
export class stackedbarchart {
sbar(box_id){
d3.select(box_id)
.select("svg")
.remove();
var margin = { top: 20, right: 160, bottom: 35, left: 30 };
var width = 1100 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = 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 + ")");
var data = [
{ country:"India", sales:100, profit:100, loss:10 },
{ country:"US", sales:100, profit:80, loss:40 },
{ country:"aus", sales:100, profit:70, loss:30 }
];
var stack = d3.stack()
.keys(["sales","profit","loss"])
.order(d3.stackOrderNone)
.offset(d3.stackOffsetNone);
var series = stack(data);
var x = d3.scaleOrdinal()
.domain(series[0].map(function(d) {
console.log(d)
return d.x; }))
.range([10, width-10], 0.02);
var y = d3.scaleLinear()
.domain([0, d3.max(series, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y; }); })])
.range([height, 0]);
var colors = ["b33040", "#d25c4d", "#f2b447", "#d9d574"];
var yAxis = d3.axisLeft(y)
.ticks(5)
.tickSize(-width, 0, 0)
.tickFormat( function(d) { return d } );
var xAxis = d3.axisBottom(x)
console.log(xAxis)
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var groups = svg.selectAll("g.cost")
.data(series)
.enter().append("g")
.attr("class", "cost")
.style("fill", function(d, i) { return colors[i]; });
var rect = groups.selectAll("rect")
.data(function(d) { return d; })
.enter()
.append("rect")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y0 + d.y); })
.attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); })
.attr("width", x.range())
.on("mouseover", function() { tooltip.style("display", null); })
.on("mouseout", function() { tooltip.style("display", "none"); })
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 15;
var yPosition = d3.mouse(this)[1] - 25;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.y);
});
var legend = svg.selectAll(".legend")
.data(colors)
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(30," + i * 19 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) {return colors.slice().reverse()[i];});
legend.append("text")
.attr("x", width + 5)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d, i) {
switch (i) {
case 0: return "sales";
case 1: return "profit";
case 2: return "loss";
}
});
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold") ;
}
}
任何帮助或向正确方向的提示将不胜感激。
答案 0 :(得分:0)
D3v4中的更改
在d3v4中进行的更改会破坏d3v3图表。 d3v3中的堆栈具有x个访问器,并使用y0
和y
来表示堆栈图的每个段的开始和结束值。结果看起来像这样:
.append("rect")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y0 + d.y); })
.attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); })
此方法不适用于d3v4 +,但似乎是您正在使用的方法。乍一看,您的代码可能基于this v3代码。
d3v4 +中的堆栈
让我们看看d3.stack在d3v4 +中产生了什么。
我们有输入数据:
var data = [
{ country:"India", sales:100, profit:100, loss:10 },
{ country:"US", sales:100, profit:80, loss:40 },
{ country:"aus", sales:100, profit:70, loss:30 }
];
还有一个堆栈生成器:
var stack = d3.stack()
.keys(["sales","profit","loss"])
.order(d3.stackOrderNone) // default value, does not need to be specified.
.offset(d3.stackOffsetNone) // default value, does not need to be specified
当我们将数据传递给堆栈生成器时,我们得到:
[/* India US AUS */
[[0, 100],[0, 100],[0, 100]], // Sales
[[100,200],[100,180],[100,170]], // Profit
[[200,210],[180,220],[170,200]] // Loss
]
如果将数组安排为表格,则列代表原始数据数组中的每个项目(代表国家的系列),行代表每个键。两个元素阵列中的每一个都代表一个堆叠的条形段。
包含给定键的所有值(例如,[[0,100],[0,100],[0,100]]
用于销售)的数组,还包含具有键名的属性“ key”。
表示单个段的每个数组(例如:[0,100]
)具有属性data
,该属性是原始数据数组中的一项(例如:{"country": "India","sales": 100,"profit": 100,"loss": 10}
)。 / p>
堆栈数组中的项目数(行数)不等于序列数(在这种情况下为国家),但等于键的数量。 >
创建天平
您遇到的第一个问题是如何指定刻度:
var x = d3.scaleOrdinal()
.domain(series[0].map(function(d) { return d.x; }))
.range([10, width-10], 0.02);
var y = d3.scaleLinear()
.domain([0, d3.max(series, function(d) { return d3.max(d, function(d) { return d.y0 + d.y; }); })])
.range([height, 0]);
因为堆栈没有创建任何y0
,y
或x
属性,所以这些都不起作用。
x刻度应该是带刻度(条形图通常使用带d3的带刻度),我们可以使用原始数据数组来创建域:
var x = d3.scaleBand() // band scale
.domain(data.map(function(d) {
return d.country; })) // return the country.
.range([10, width-10]);
y标度需要访问d [0]和d [1],而不是d.y0和d.y:
var y = d3.scaleLinear()
.domain([0, d3.max(series, function(d) {
return d3.max(d, function(d) {
return d[0] + d[1]; }); })]) // access stack values (not d.y, d.y0)
.range([height, 0]);
附加矩形
现在让我们移至附加矩形的位置:
.append("rect")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y0 + d.y); })
.attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); })
.attr("width", x.range())
由于d.x未定义,我们可以使用x(d.data.country)
。 d.y0
和d.y
出现的地方,我们需要替换d[0]
和d[1]
。最后,x.range()
几乎是图形的宽度,我们可以改用x.bandwidth()
,它是单个条形的宽度。
下面是您的代码(从定义边距开始),其中包含以下更新:
var margin = { top: 20, right: 160, bottom: 35, left: 30 };
var width = 500 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var svg = 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 + ")");
var data = [
{ country:"India", sales:100, profit:100, loss:10 },
{ country:"US", sales:100, profit:80, loss:40 },
{ country:"Aus", sales:100, profit:70, loss:30 },
{ country:"NZ", sales:100, profit:70, loss:30 }
];
var stack = d3.stack()
.keys(["sales","profit","loss"])
.order(d3.stackOrderNone)
.offset(d3.stackOffsetNone);
var series = stack(data);
var x = d3.scaleBand() // band scale
.domain(data.map(function(d) {
return d.country; })) // return the country.
.range([10, width-10])
.padding(0.1); // space between (value between 0 and 1).
var y = d3.scaleLinear()
.domain([0, d3.max(series, function(d) {
return d3.max(d, function(d) {
return d[0] + d[1]; }); })]) // access stack values (not d.y, d.y0)
.range([height, 0]);
// color scale:
var colors = d3.scaleOrdinal()
.range(["b33040", "#d25c4d", "#f2b447", "#d9d574"])
.domain(series.map(function(d) { return d.key; }));
var yAxis = d3.axisLeft(y)
.ticks(5)
.tickSize(-width, 0, 0)
.tickFormat( function(d) { return d } );
var xAxis = d3.axisBottom(x)
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var groups = svg.selectAll("g.cost")
.data(series)
.enter().append("g")
.attr("class", "cost")
.style("fill", function(d) { return colors(d); });
// More changes:
var rect = groups.selectAll("rect")
.data(function(d) { return d; })
.enter()
.append("rect")
.attr("x", function(d) { return x(d.data.country); }) // Access country.
.attr("y", function(d) { return y(d[0] + d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[0] + d[1]); })
.attr("width", x.bandwidth())
// Minor changes:
var legend = svg.selectAll(".legend")
.data(series)
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(30," + i * 19 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) {
return colors(d.key);
});
legend.append("text")
.attr("x", width + 5)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d) { return d.key; })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
为简化代码段,我删除了鼠标交互
创建图例
这可以简化一点,但这不是问题的一部分,不过,我将其与色标一起包括在这里。