我一直在使用带有以下代码的堆叠条形图示例here:
var data = [
{month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960, dates: -400},
{month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960, dates: -400},
{month: "Q3-2016", apples: 640, bananas: 960, cherries: -640, dates: -600},
{month: "Q4-2016", apples: 320, bananas: 480, cherries: -640, dates: -400}
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries", "dates"])
.offset(d3.stackOffsetDiverging)
(data);
var svg = d3.select("svg"),
margin = {top: 20, right: 30, bottom: 30, left: 60},
width = +svg.attr("width"),
height = +svg.attr("height");
var x = d3.scaleBand()
.domain(data.map(function(d) { return d.month; }))
.rangeRound([margin.left, width - margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom, margin.top]);
var z = d3.scaleOrdinal(d3.schemeCategory10);
svg.append("g")
.selectAll("g")
.data(series)
.enter().append("g")
.attr("fill", function(d) { return z(d.key); })
.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr("width", x.bandwidth)
.attr("x", function(d) { return x(d.data.month); })
.attr("y", function(d) { return y(d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[1]); })
svg.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
function stackMin(serie) {
return d3.min(serie, function(d) { return d[0]; });
}
function stackMax(serie) {
return d3.max(serie, function(d) { return d[1]; });
}
根据示例的代码不支持转换或重绘,所以我一直在尝试将general update pattern的原则应用到它,以便我可以在我的应用程序中使用它。
我不熟悉D3v4以及'追加'的性质。困惑我。我看到两个'进入'在同一个追加方法链中,所以我试图将它们分成自己的声明,如:
var join1 = .selectAll("g")
.data(series)
var join2Update = .selectAll("rect")
.data(function(d) { return d; })
var join2Enter= join2.enter()
join2Enter
.append("rect")
.merge(join2Update)
.transition()
.attr("width", x.bandwidth)
.attr("x", function(d) { return x(d.data.month); })
.attr("y", function(d) { return y(d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[1]); })
但除了打破图表之外,它并没有做多少事情!我坦率地说,在整个事情上有点迷失,任何帮助都会非常感激。
答案 0 :(得分:3)
我确实对代码进行了一些修改以使其更新,我会指出我所做的一些更改,如果还有其他任何不清楚的问题,你可以问一下。
我改变的主要内容是,在我们的数据集中,为简单起见,我们有两个类别,以便我们可以根据这样的输入更新我们的数据
var keys = ["apples" + input, "bananas" + input];
这里的输入变量最初是像这样选择的
var input = d3.selectAll(".opt").property("value");
当我们手动更新它时,我们会得到像这样的新数据
d3.selectAll(".opt").on("change", function() {
update(data, this.value)
})
我们创建了一个包含series
数据集的条形图组,然后将其与另一个变量一起引用,而不是直接在矩形上附加一个元素。
var barGroups = svg.selectAll("g.layer")
.data(series);
barGroups.exit().remove();
barGroups.enter().insert("g", ".x-axis")
.classed('layer', true);
这是您之前提到的代码的更新模式部分:
var bars = svg.selectAll("g.layer").selectAll("rect")
.data(function(d) { return d; });
bars.exit().remove();
bars = bars
.enter()
.append("rect")
.attr("width", x.bandwidth())
.attr("x", d => x(d.data.month))
.merge(bars)
bars.transition().duration(750)
.attr("y", d => y(d[1]))
.attr("height", d => Math.abs(y(d[0])) - y(d[1]));
应该是它,看看下面的代码片段,看看它是如何运作的。
var data = [
{month: "Q1-2016", apples_1: -400, bananas_1: 920, apples_2: -196, bananas_2: 840},
{month: "Q2-2016", apples_1: -400, bananas_1: 440, apples_2: -960, bananas_2: 600},
{month: "Q3-2016", apples_1: -600, bananas_1: 960, apples_2: -640, bananas_2: 640},
{month: "Q4-2016", apples_1: -400, bananas_1: 480, apples_2: -640, bananas_2: 320}
];
var margin = {top: 35, right: 145, bottom: 35, left: 45},
width = 650 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
var svg = d3.select("#chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand()
.rangeRound([0, width])
.padding(0.1);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var z = d3.scaleOrdinal()
.range(["steelblue","darkorange"]);
svg.append("g")
.attr("class","x-axis");
svg.append("g")
.attr("class", "y-axis");
var input = d3.selectAll(".opt").property("value");
d3.selectAll(".opt").on("change", function() {
update(data, this.value)
})
update(data, input);
function update(data, input) {
var keys = ["apples" + input, "bananas" + input];
var series = d3.stack()
.keys(keys)
.offset(d3.stackOffsetDiverging)
(data);
x.domain(data.map(d => d.month));
y.domain([
d3.min(series, stackMin),
d3.max(series, stackMax)
]).nice();
var barGroups = svg.selectAll("g.layer")
.data(series);
barGroups.exit().remove();
barGroups.enter().insert("g", ".x-axis")
.classed('layer', true);
svg.selectAll("g.layer")
.transition().duration(750)
.attr("fill", d => z(d.key));
var bars = svg.selectAll("g.layer").selectAll("rect")
.data(function(d) { return d; });
bars.exit().remove();
bars = bars
.enter()
.append("rect")
.attr("width", x.bandwidth())
.attr("x", d => x(d.data.month))
.merge(bars)
bars.transition().duration(750)
.attr("y", d => y(d[1]))
.attr("height", d => Math.abs(y(d[0])) - y(d[1]));
svg.selectAll(".x-axis").transition().duration(750)
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
svg.selectAll(".y-axis").transition().duration(750)
.call(d3.axisLeft(y));
function stackMin(serie) {
return d3.min(serie, function(d) { return d[0]; });
}
function stackMax(serie) {
return d3.max(serie, function(d) { return d[1]; });
}
}
body {
margin: auto;
width: 850px;
}
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
select something
<select class="opt">
<option value="_1">1</option>
<option value="_2">2</option>
</select><br>
<svg id="chart"></svg>