gpt4 book ai didi

javascript - 无法创建堆叠条形图?

转载 作者:搜寻专家 更新时间:2023-10-30 21:56:15 24 4
gpt4 key购买 nike

我正在使用 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") ;

}
}

任何有关正确方向的帮助或提示都将不胜感激。

最佳答案

D3v4 的变化

d3v4 中的更改会破坏 d3v3 图表。 d3v3 中的堆栈有 x 访问器,并使用 y0y 来表示堆栈图表每个部分的开始值和结束值。结果看起来像这样:

 .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}).

堆栈数组中的项目数(行数)不等于系列数(在本例中为国家/地区),但等于键数。

创建比例

您遇到的第一个问题是如何指定比例:

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]);

因为堆栈不创建任何 y0yx 属性,所以这些将不起作用。

x刻度应该是band刻度(条形图一般用d3的band刻度),我们可以只用原始数据数组创建域:

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.y0d.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>

为了简化代码片段,我删除了鼠标交互

创造传奇

这可以稍微简化一点,它不是问题的一部分,尽管如此,我还是将它连同色标一起包含在这里。

关于javascript - 无法创建堆叠条形图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55533823/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com